Quelles sont les différences entre les modèles de conception Abstract Factory et Factory?

455

Je sais qu'il existe de nombreux articles sur les différences entre ces deux modèles, mais il y a quelques choses que je ne peux pas trouver.

D'après ce que j'ai lu, je vois que le modèle de méthode d'usine vous permet de définir comment créer un seul produit concret mais en masquant l'implémentation au client car il verra un produit générique. Ma première question concerne l'usine abstraite. Son rôle est-il de vous permettre de créer des familles d'objets concrets dans (cela peut dépendre de quelle usine spécifique vous utilisez) plutôt qu'un simple objet concret? L'usine abstraite ne renvoie-t-elle qu'un très grand objet ou plusieurs objets selon les méthodes que vous appelez?

Mes deux dernières questions portent sur une seule citation que je ne comprends pas bien que j'ai vue à de nombreux endroits:

Une différence entre les deux est qu'avec le modèle Abstract Factory, une classe délègue la responsabilité de l'instanciation d'objet à un autre objet via la composition tandis que le modèle Factory Method utilise l'héritage et s'appuie sur une sous-classe pour gérer l'instanciation d'objet souhaitée.

Ma compréhension est que le modèle de méthode d'usine a une interface Creator qui fera que ConcreteCreator sera en charge de savoir quel ConcreteProduct instancier. Est-ce ce que cela signifie en utilisant l'héritage pour gérer l'instanciation d'objets?

En ce qui concerne cette citation, comment le modèle Abstract Factory délègue-t-il exactement la responsabilité de l'instanciation d'objet à un autre objet via la composition? Qu'est-ce que ça veut dire? Il semble que le modèle Abstract Factory utilise également l'héritage pour faire le processus de construction à mes yeux, mais là encore, j'apprends encore ces modèles.

Toute aide, en particulier avec la dernière question, serait grandement appréciée.

Silverbolt
la source
Voir «comment l'instance a été créée» du point de vue du client, vous aiderait à comprendre le devis.
Karthik Bose
@nawfal, les réponses dans ce fil sont horribles.
jaco0646

Réponses:

494

La différence entre les deux

La principale différence entre une "méthode d'usine" et une "usine abstraite" est que la méthode d'usine est une méthode unique et qu'une usine abstraite est un objet. Je pense que beaucoup de gens confondent ces deux termes et commencent à les utiliser de manière interchangeable. Je me souviens que j'avais du mal à trouver exactement quelle était la différence quand je les apprenais.

Parce que la méthode d'usine n'est qu'une méthode, elle peut être remplacée dans une sous-classe, d'où la seconde moitié de votre devis:

... le modèle Factory Method utilise l'héritage et s'appuie sur une sous-classe pour gérer l'instanciation d'objet souhaitée.

La citation suppose qu'un objet appelle sa propre méthode d'usine ici. Par conséquent, la seule chose qui pourrait changer la valeur de retour serait une sous-classe.

L'usine abstraite est un objet qui comporte plusieurs méthodes d'usine. En regardant la première moitié de votre devis:

... avec le modèle Abstract Factory, une classe délègue la responsabilité de l'instanciation d'objet à un autre objet via la composition ...

Ce qu'ils disent, c'est qu'il y a un objet A, qui veut faire un objet Foo. Au lieu de créer l'objet Foo lui-même (par exemple, avec une méthode d'usine), il va obtenir un objet différent (l'usine abstraite) pour créer l'objet Foo.

Exemples de code

Pour vous montrer la différence, voici une méthode d'usine utilisée:

class A {
    public void doSomething() {
        Foo f = makeFoo();
        f.whatever();   
    }

    protected Foo makeFoo() {
        return new RegularFoo();
    }
}

class B extends A {
    protected Foo makeFoo() {
        //subclass is overriding the factory method 
        //to return something different
        return new SpecialFoo();
    }
}

Et voici une usine abstraite en cours d'utilisation:

class A {
    private Factory factory;

    public A(Factory factory) {
        this.factory = factory;
    }

    public void doSomething() {
        //The concrete class of "f" depends on the concrete class
        //of the factory passed into the constructor. If you provide a
        //different factory, you get a different Foo object.
        Foo f = factory.makeFoo();
        f.whatever();
    }
}

interface Factory {
    Foo makeFoo();
    Bar makeBar();
    Aycufcn makeAmbiguousYetCommonlyUsedFakeClassName();
}

//need to make concrete factories that implement the "Factory" interface here
Tom Dalling
la source
15
C'est une excellente explication. Mais, quelle est la partie la plus importante qui reste sans réponse, et c'est: quand en utiliser un, et quand l'autre modèle?
croraf
11
Pas sûr que ce soit correct. Je suis sûr que la méthode d'usine est un modèle de conception nommé d'après les méthodes d'usine, mais implique une structure de classe et un héritage. Ce n'est pas une méthode unique.
Aviv Cohn
2
Il est donc correct de dire: la méthode Factory peut être une méthode dans toutes les classes régulières avec des objectifs différents. Mais la Abstract Factory est une classe / objet utilisé par un client et est SEULEMENT responsable de la création de certains produits dans une famille?
Hieu Nguyen
Votre utilisation du mot "Super" dans "SuperFoo" signifie-t-elle simplement un cas particulier de Foo, ou signifie-t-elle réellement une super classe? Comme je l'ai supposé, ce doit être une sous-classe.
dahui
@dahui Oui, c'est une sous-classe. Je l'ai changé SpecialFoopour être plus clair.
Tom Dalling
125

L'usine abstraite crée une classe de base avec des méthodes abstraites définissant les méthodes des objets à créer. Chaque classe d'usine qui dérive la classe de base peut créer sa propre implémentation de chaque type d'objet.

entrez la description de l'image ici

La méthode d'usine est juste une méthode simple utilisée pour créer des objets dans une classe. Il est généralement ajouté dans la racine agrégée (la Orderclasse a une méthode appelée CreateOrderLine)

entrez la description de l'image ici

Usine abstraite

Dans l'exemple ci-dessous, nous concevons une interface afin de pouvoir dissocier la création de files d'attente d'un système de messagerie et donc créer des implémentations pour différents systèmes de files d'attente sans avoir à changer la base de code.

interface IMessageQueueFactory
{
  IMessageQueue CreateOutboundQueue(string name);
  IMessageQueue CreateReplyQueue(string name);
}

public class AzureServiceBusQueueFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new AzureMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new AzureResponseMessageQueue(/*....*/);
      }

}

public class MsmqFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new MsmqMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new MsmqResponseMessageQueue(/*....*/);
      }
}

Méthode d'usine

Le problème dans les serveurs HTTP est que nous avons toujours besoin d'une réponse pour chaque demande.

public interface IHttpRequest
{
    // .. all other methods ..

    IHttpResponse CreateResponse(int httpStatusCode);
}

Sans la méthode d'usine, les utilisateurs du serveur HTTP (c'est-à-dire les programmeurs) seraient obligés d'utiliser des classes spécifiques à l'implémentation, ce qui irait à l'encontre du but de l' IHttpRequestinterface.

Par conséquent, nous introduisons la méthode d'usine afin que la création de la classe de réponse soit également abstraite.

Sommaire

La différence est que l' objectif de la classe contenant une méthode de fabrique n'est pas de créer des objets , alors qu'une fabrique abstraite ne doit être utilisée que pour créer des objets.

Il faut être prudent lors de l'utilisation des méthodes d'usine car il est facile de casser le LSP ( principe de substitution Liskov ) lors de la création d'objets.

jgauffin
la source
3
Pourquoi avons-nous besoin d'un produit concret?
Andrew S
60
Parce que personne ne veut investir dans des idées.
jgauffin
4
L'Usine abstraite devrait créer plus que juste Button()pour faire une «famille de produits connexes». Par exemple, l'exemple canonique GoF crée ScrollBar()et Window(). L'avantage est que Abstract Factory peut appliquer un thème commun à ses multiples produits.
jaco0646
Jaco a raison. Considérez que les deux diagrammes UML sont essentiellement les mêmes (à côté de l'UML Abstract Factory qui est faux). Dans les deux cas, le client appelle une méthode d'usine pour créer un seul produit.
cobby
1
@AndrewS: Pour répondre à votre question. Si nous n'avons pas besoin d'avoir différents produits concrets (classes) pour la même abstraction (interface), nous avons probablement besoin du modèle de constructeur à la place et non du modèle d'usine. (mieux vaut tard que jamais;))
jgauffin
95

Les différences entre les modèles de conception AbstractFactory et Factory sont les suivantes:

  • La méthode Factory est utilisée pour créer un seul produit, mais Abstract Factory concerne la création de familles de produits liés ou dépendants.
  • Le modèle Factory Method expose une méthode au client pour créer l'objet alors que dans le cas de Abstract Factory, ils exposent une famille d'objets associés qui peuvent être constitués de ces méthodes Factory.
  • Le modèle Factory Method masque la construction d'un seul objet, tandis que Abstract Factory masque la construction d'une famille d'objets associés. Les usines abstraites sont généralement implémentées en utilisant (un ensemble de) méthodes d'usine.
  • Le modèle Factory abstrait utilise la composition pour déléguer la responsabilité de créer un objet à une autre classe tandis que le modèle de conception de la méthode Factory utilise l'héritage et s'appuie sur une classe ou une sous-classe dérivée pour créer un objet.
  • L'idée derrière le modèle Factory Method est qu'il permet le cas où un client ne sait pas quelles classes concrètes il devra créer au moment de l'exécution, mais veut juste obtenir une classe qui fera le travail alors que le modèle Abstract Factory est mieux utilisé lorsque votre système doit créer plusieurs familles de produits ou que vous souhaitez fournir une bibliothèque de produits sans exposer les détails de mise en œuvre.!

Implémentation du modèle de méthode d'usine: Méthode d'usine UML

Mise en œuvre du modèle d'usine abstraite:

Abstract Factory UML

Vibha Sanskrityayan
la source
13
Mmm, je ne suis pas sûr de l'exemple de l'usine abstraite. Je pense que l'usine de formes et l'usine de couleurs devraient implémenter les mêmes méthodes. Mais si j'ai raison, l'échantillon n'a aucun sens.
Joaquin Iurchuk
4
Les puces sont correctes; cependant, les deux diagrammes sont complètement faux et très trompeurs. Voir le schéma ci-dessous de @Trying pour un modèle précis de Abstract Factory.
jaco0646
1
je dois convenir que les 2 diagrammes sont vraiment trompeurs. Je les ai vus sur le site Web tutorialspoint et pour être honnête, je ne suis pas d'accord à 100% avec eux. Les descriptions semblent bonnes cependant
SoftwareDeveloper
C'est très trompeur.
diyoda_
Plus de 50 votes positifs et les diagrammes sont très faux. Preuve que vous ne pouvez pas faire confiance à de nombreuses réponses de modèle de conception sur SO.
Fuhrmanator
27

La principale différence entre Abstract Factory et Factory Method est que Abstract Factory est implémenté par Composition ; mais la méthode d'usine est implémentée par l'héritage .

Oui, vous avez bien lu: la principale différence entre ces deux modèles est l'ancien débat entre composition et héritage .

Les diagrammes UML se trouvent dans le livre (GoF). Je veux fournir des exemples de code, car je pense que la combinaison des exemples des deux premières réponses dans ce fil donnera une meilleure démonstration que l'une ou l'autre réponse seule. De plus, j'ai utilisé la terminologie du livre dans les noms de classe et de méthode.

Usine abstraite

  1. Le point le plus important à saisir ici est que la fabrique abstraite est injectée dans le client. C'est pourquoi nous disons que Abstract Factory est implémenté par Composition. Souvent, un cadre d'injection de dépendances effectuerait cette tâche; mais un cadre n'est pas requis pour DI.
  2. Le deuxième point critique est que les usines concrètes ici ne sont pas des implémentations de méthode d'usine! Un exemple de code pour la méthode d'usine est présenté ci-dessous.
  3. Et enfin, le troisième point à noter est la relation entre les produits: dans ce cas les files d'attente sortantes et de réponse. Une usine de béton produit des files d'attente Azure, l'autre MSMQ. Le GoF se réfère à cette relation de produit comme une "famille" et il est important de savoir que la famille dans ce cas ne signifie pas la hiérarchie des classes.
public class Client {
    private final AbstractFactory_MessageQueue factory;

    public Client(AbstractFactory_MessageQueue factory) {
        // The factory creates message queues either for Azure or MSMQ.
        // The client does not know which technology is used.
        this.factory = factory;
    }

    public void sendMessage() {
        //The client doesn't know whether the OutboundQueue is Azure or MSMQ.
        OutboundQueue out = factory.createProductA();
        out.sendMessage("Hello Abstract Factory!");
    }

    public String receiveMessage() {
        //The client doesn't know whether the ReplyQueue is Azure or MSMQ.
        ReplyQueue in = factory.createProductB();
        return in.receiveMessage();
    }
}

public interface AbstractFactory_MessageQueue {
    OutboundQueue createProductA();
    ReplyQueue createProductB();
}

public class ConcreteFactory_Azure implements AbstractFactory_MessageQueue {
    @Override
    public OutboundQueue createProductA() {
        return new AzureMessageQueue();
    }

    @Override
    public ReplyQueue createProductB() {
        return new AzureResponseMessageQueue();
    }
}

public class ConcreteFactory_Msmq implements AbstractFactory_MessageQueue {
    @Override
    public OutboundQueue createProductA() {
        return new MsmqMessageQueue();
    }

    @Override
    public ReplyQueue createProductB() {
        return new MsmqResponseMessageQueue();
    }
}

Méthode d'usine

  1. Le point le plus important à saisir ici est que ConcreteCreator c'est le client. En d'autres termes, le client est une sous-classe dont le parent définit le factoryMethod(). C'est pourquoi nous disons que la méthode Factory est implémentée par héritage.
  2. Le deuxième point critique est de se rappeler que le modèle de méthode d'usine n'est rien d'autre qu'une spécialisation du modèle de méthode de modèle. Les deux modèles partagent une structure identique. Ils ne diffèrent que par leur objectif. La méthode Factory est créative (elle construit quelque chose) tandis que la méthode Template est comportementale (elle calcule quelque chose).
  3. Et enfin, le troisième point à noter est que la Creatorclasse (parent) invoque la sienne factoryMethod(). Si nous supprimons anOperation()de la classe parent, ne laissant qu'une seule méthode derrière, ce n'est plus le modèle de méthode d'usine. En d'autres termes, la méthode Factory ne peut pas être implémentée avec moins de deux méthodes dans la classe parente; et l'un doit invoquer l'autre.
public abstract class Creator {
    public void anOperation() {
        Product p = factoryMethod();
        p.whatever();
    }

    protected abstract Product factoryMethod();
}

public class ConcreteCreator extends Creator {
    @Override
    protected Product factoryMethod() {
        return new ConcreteProduct();
    }
}

Divers & Modèles d'usine divers

Sachez que bien que le GoF définisse deux modèles Factory différents, ce ne sont pas les seuls modèles Factory existants. Ce ne sont même pas nécessairement les modèles d'usine les plus couramment utilisés. Un troisième exemple célèbre est le modèle d'usine statique de Josh Bloch de Java efficace. Le livre Head First Design Patterns comprend un autre modèle qu'ils appellent Simple Factory.

Ne tombez pas dans le piège de supposer que chaque modèle Factory doit correspondre à celui du GoF.

jaco0646
la source
3
Grande et très claire réponse basée sur de bons exemples, le meilleur dans ce sujet OMI.
Luke Duda
Grande explication. +1 pour la méthode Factory doit appeler son point de méthode Factory abstrait. Sur ce point, c'est très clair, sans comprendre ce point: si nous avons une méthode de fabrique qui n'est pas invoquée par elle-même, cela implique qu'elle sera utilisée par une autre classe qui la composera et ses sous-classes seront injectées, elle se transforme en fabrique abstraite , la différence devient moins claire si le point que la méthode d'usine abstraite doit être invoquée par l'usine elle-même comme le modèle de méthode de modèle n'est pas compris
nits.kk
Encore une question-remarque. La méthode doit-elle factoryMethod()toujours être protecteddans le modèle "Méthode d'usine"? (Je pense que oui)
Yaroslav Fedoruk
1
@YaroslavFedoruk, le livre du GoF permet des publicméthodes d'usine, et la méthode n'a même pas besoin d'être abstract; mais le point critique est que la méthode est destinée à l'héritage, elle ne peut donc pas (par exemple) être soit staticou final. J'ai fait la méthode protectedet abstractici pour mettre en évidence l'extensibilité (requise).
jaco0646
@ nits.kk, vous pourriez être intéressé par une réponse connexe .
jaco0646
26

Abstract Factory est une interface pour créer des produits associés, mais Factory Method n'est qu'une méthode. Abstract Factory peut être implémenté par plusieurs méthodes d'usine.

Abstract Factory UML

En essayant
la source
10
Vous avez déjà posté la même réponse ici . Si vous pensez que cette question est similaire, marquez-la plutôt comme doublon.
Ja͢ck
11

Considérez cet exemple pour une compréhension facile.

Que proposent les entreprises de télécommunications? Haut débit, ligne téléphonique et mobile par exemple et on vous demande de créer une application pour proposer leurs produits à leurs clients.

Généralement, ce que vous feriez ici, c'est que la création des produits, c'est-à-dire le haut débit, la ligne téléphonique et le mobile, se fait via votre méthode d'usine où vous savez quelles propriétés vous avez pour ces produits et c'est assez simple.

Maintenant, la société veut offrir à ses clients un ensemble de leurs produits, à savoir le haut débit, la ligne téléphonique et le mobile, et voici la Abstract Factory à jouer.

En d'autres termes, Abstract Factory est la composition d'autres usines qui sont responsables de la création de leurs propres produits et Abstract Factory sait comment mettre ces produits en valeur par rapport à ses propres responsabilités.

Dans ce cas, le BundleFactoryest l'usine abstraite BroadbandFactory, PhonelineFactoryet MobileFactorysont les Factory. Pour simplifier davantage, ces usines auront une méthode d'usine pour initialiser les produits individuels.

Consultez l'exemple de code ci-dessous:

public class BroadbandFactory : IFactory {
    public static Broadband CreateStandardInstance() {
        // broadband product creation logic goes here
    }
}

public class PhonelineFactory : IFactory {
    public static Phoneline CreateStandardInstance() {
        // phoneline product creation logic goes here
    }
}

public class MobileFactory : IFactory {
    public static Mobile CreateStandardInstance() {
        // mobile product creation logic goes here
    }
}

public class BundleFactory : IAbstractFactory {

    public static Bundle CreateBundle() {
        broadband = BroadbandFactory.CreateStandardInstance();
        phoneline = PhonelineFactory.CreateStandardInstance();
        mobile = MobileFactory.CreateStandardInstance();

        applySomeDiscountOrWhatever(broadband, phoneline, mobile);
    }

    private static void applySomeDiscountOrWhatever(Broadband bb, Phoneline pl, Mobile m) {
        // some logic here
        // maybe manange some variables and invoke some other methods/services/etc.
    }
}

J'espère que cela t'aides.

Abdul Munim
la source
1
Il n'y a pas de staticméthode dans les deux modèles d'usine GoF. C'est faux.
jaco0646
5

Exemple réel. (Facile à retenir)

Usine

Imaginez que vous construisez une maison et que vous vous approchez d'un charpentier pour une porte. Vous donnez la mesure de la porte et vos besoins, et il construira une porte pour vous. Dans ce cas, le menuisier est une usine de portes. Vos spécifications sont des entrées pour l'usine et la porte est la sortie ou le produit de l'usine.

Usine abstraite

Maintenant, considérons le même exemple de la porte. Vous pouvez vous rendre chez un menuisier, ou vous pouvez vous rendre dans un magasin de portes en plastique ou un magasin de PVC. Tous sont des usines de porte. En fonction de la situation, vous décidez quel type d'usine vous devez approcher. C'est comme une usine abstraite.

J'ai expliqué ici à la fois le modèle de méthode d'usine et le modèle d'usine abstrait en commençant par ne pas les utiliser en expliquant les problèmes, puis en résolvant les problèmes en utilisant les modèles ci-dessus https://github.com/vikramnagineni/Design-Patterns/tree/master

Vikram Babu Nagineni
la source
3

Disons clairement que la plupart du temps dans le code de production, nous utilisons un modèle d'usine abstrait parce que la classe A est programmée avec l'interface B. Et A doit créer des instances de B. Donc, A doit avoir un objet d'usine pour produire des instances de B Donc, A ne dépend d'aucune instance concrète de B. J'espère que cela aide.

Adrian Liu
la source
3

Comprendre les différences de motivations:

Supposons que vous construisez un outil où vous avez des objets et une implémentation concrète des interrelations des objets. Puisque vous prévoyez des variations dans les objets, vous avez créé une indirection en assignant la responsabilité de créer des variantes des objets à un autre objet ( nous l'appelons usine abstraite ). Cette abstraction trouve un avantage important car vous prévoyez de futures extensions nécessitant des variantes de ces objets.

Une autre motivation assez intrigante dans cette ligne de pensée est un cas où tout ou partie des objets de l'ensemble du groupe auront une variante correspondante. En fonction de certaines conditions, l'une ou l'autre des variantes sera utilisée et dans chaque cas, tous les objets doivent être de la même variante. Cela peut être un peu contre-intuitif à comprendre car nous avons souvent tendance à penser que - tant que les variantes d'un objet suivent un contrat uniforme commun ( interface au sens large) ), le code d'implémentation concret ne doit jamais se casser. Le fait fascinant ici est que, ce n'est pas toujours le cas, en particulier lorsque le comportement attendu ne peut pas être modélisé par un contrat de programmation.

Un simple ( emprunt de l'idée au GoF ) est toute application graphique, par exemple un moniteur virtuel qui émule l'apparence de MS ou Mac ou Fedora OS. Ici, par exemple, lorsque tous les objets widget tels que fenêtre, bouton, etc. ont une variante MS à l'exception d'une barre de défilement dérivée de la variante MAC, le but de l'outil échoue gravement.

Ces cas ci-dessus forment le besoin fondamental de Abstract Factory Pattern .

D'un autre côté, imaginez que vous écrivez un framework afin que de nombreuses personnes puissent construire différents outils ( comme celui des exemples ci-dessus ) en utilisant votre framework. Par l'idée même d'un framework, vous n'en avez pas besoin, bien que vous ne puissiez pas utiliser des objets concrets dans votre logique. Vous mettez plutôt des contrats de haut niveau entre divers objets et comment ils interagissent. Alors que vous (en tant que développeur de framework ) restez à un niveau très abstrait, chaque constructeur de l'outil est obligé de suivre vos constructions de framework. Cependant, ils ( les constructeurs d'outils ) ont la liberté de décider quel objet à construire et comment tous les objets qu'ils créent interagiront. Contrairement au cas précédent ( de Abstract Factory Pattern ), vous (en tant que créateur de framework) n'ont pas besoin de travailler avec des objets concrets dans ce cas; et peut plutôt rester au niveau du contrat des objets. De plus, contrairement à la deuxième partie des motivations précédentes, vous ou les constructeurs d'outils n'avez jamais de situations de mélange d'objets de variantes. Ici, alors que le code cadre reste au niveau du contrat, chaque constructeur d'outils est limité ( par la nature du cas lui-même ) à utiliser ses propres objets. Les créations d'objets dans ce cas sont déléguées à chaque implémenteur et les fournisseurs de framework fournissent simplement des méthodes uniformes pour créer et renvoyer des objets. De telles méthodes sont inévitables pour le développeur de framework pour continuer avec leur code et ont un nom spécial appelé méthode Factory ( Factory Method Pattern pour le modèle sous-jacent ).

Quelques notes:

  • Si vous êtes familier avec la `` méthode de modèle '', alors vous verriez que les méthodes d'usine sont souvent invoquées à partir de méthodes de modèle dans le cas de programmes appartenant à n'importe quelle forme de cadre. En revanche, les méthodes de modèle de programmes d'application sont souvent une implémentation simple d'un algorithme spécifique et sans méthodes d'usine.
  • En outre, pour l'intégralité des pensées, en utilisant le cadre ( mentionné ci-dessus ), lorsqu'un constructeur d'outils construit un outil, à l'intérieur de chaque méthode d'usine, au lieu de créer un objet concret, il / elle peut déléguer davantage la responsabilité à un résumé -objet d'usine, à condition que le constructeur d'outils prévoit des variations des objets concrets pour de futures extensions.

Exemple de code:

//Part of framework-code
BoardGame {
    Board createBoard() //factory method. Default implementation can be provided as well
    Piece createPiece() //factory method

    startGame(){        //template method
         Board borad = createBoard()
         Piece piece = createPiece()
         initState(board, piece)
    }
}


//Part of Tool-builder code
Ludo inherits  BoardGame {
     Board createBoard(){ //overriding of factory method
         //Option A: return new LudoBoard() //Lodu knows object creation
         //Option B: return LudoFactory.createBoard() //Lodu asks AbstractFacory
     }
….
}

//Part of Tool-builder code
Chess inherits  BoardGame {
    Board createBoard(){ //overriding of factory method
        //return a Chess board
    }
    ….
}
KGhatak
la source
3
  1. Ma première question concerne l'usine abstraite. Son rôle est-il de vous permettre de créer des familles d'objets concrets dans (cela peut dépendre de quelle usine spécifique vous utilisez) plutôt qu'un simple objet concret?

Oui. L'intention de Abstract Factory est:

Fournir une interface pour créer des familles d'objets liés ou dépendants sans spécifier leurs classes concrètes.


  1. L'usine abstraite ne renvoie-t-elle qu'un très grand objet ou plusieurs objets selon les méthodes que vous appelez?

Idéalement, il devrait renvoyer un objet par la méthode que le client invoque.

  1. Ma compréhension est que le modèle de méthode d'usine a une interface Creator qui fera que ConcreteCreator sera en charge de savoir quel ConcreteProduct instancier. Est-ce ce que cela signifie en utilisant l'héritage pour gérer l'instanciation d'objets?

Oui. La méthode d'usine utilise l'héritage.

  1. Abstract Factory pattern délègue la responsabilité de l'instanciation d'objet à un autre objet via la composition? Qu'est-ce que ça veut dire?

AbstractFactory définit une FactoryMethod et ConcreteFactory est responsable de la construction d'un ConcreteProduct. Suivez simplement l'exemple de code dans cet article .

Vous pouvez trouver plus de détails dans les articles SE associés:

Quelle est la différence fondamentale entre les motifs d'usine et les motifs d'usine abstraits?

Modèles de conception: méthode Factory vs Factory vs Abstract Factory

Ravindra babu
la source
3

La méthode Factory repose sur l'héritage: la création d'objets est déléguée à des sous-classes, qui implémentent la méthode Factory pour créer des objets.

Abstract Factory s'appuie sur la composition des objets: la création d'objets est implémentée dans des méthodes exposées dans l'interface d'usine.

Diagramme de haut niveau du modèle d'usine et d'usine abstraite,

diagramme

Pour plus d'informations sur la méthode Factory, consultez cet article .

Pour plus d'informations sur la méthode de fabrique abstraite, consultez cet article .

user2266614
la source
2

Pour le rendre très simple avec une interface minimale et veuillez concentrer "// 1":

class FactoryProgram
    {
        static void Main()
        {
            object myType = Program.MyFactory("byte");
            Console.WriteLine(myType.GetType().Name);

            myType = Program.MyFactory("float"); //3
            Console.WriteLine(myType.GetType().Name);

            Console.ReadKey();
        }

        static object MyFactory(string typeName)
        {
            object desiredType = null; //1
            switch (typeName)
            {
                case "byte": desiredType = new System.Byte(); break; //2
                case "long": desiredType = new System.Int64(); break;
                case "float": desiredType = new System.Single(); break;
                default: throw new System.NotImplementedException();
            }
            return desiredType;
        }
    }

Voici les points importants: 1. Les mécanismes Factory & AbstractFactory doivent utiliser l'héritage (System.Object-> byte, float ...); Donc, si vous avez un héritage dans le programme, Factory (Abstract Factory ne serait probablement pas là) est déjà là par conception 2. Le créateur (MyFactory) connaît le type concret et renvoie donc l'objet de type concret à l'appelant (Main); En résumé, le type de retour d'usine serait une interface.

interface IVehicle { string VehicleName { get; set; } }
interface IVehicleFactory
    {
        IVehicle CreateSingleVehicle(string vehicleType);
    }
class HondaFactory : IVehicleFactory
    {
        public IVehicle CreateSingleVehicle(string vehicleType)
        {
            switch (vehicleType)
            {
                case "Sports": return new SportsBike();
                case "Regular":return new RegularBike();
                default: throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", vehicleType));
            }
        }
    }
class HeroFactory : IVehicleFactory
    {
        public IVehicle CreateSingleVehicle(string vehicleType)
        {
            switch (vehicleType)
            {
                case "Sports":  return new SportsBike();
                case "Scooty": return new Scooty();
                case "DarkHorse":return new DarkHorseBike();
                default: throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", vehicleType));
            }
        }
    }

class RegularBike : IVehicle { public string VehicleName { get { return "Regular Bike- Name"; } set { VehicleName = value; } } }
class SportsBike : IVehicle { public string VehicleName { get { return "Sports Bike- Name"; } set { VehicleName = value; } } }
class RegularScooter : IVehicle { public string VehicleName { get { return "Regular Scooter- Name"; } set { VehicleName = value; } } }
class Scooty : IVehicle { public string VehicleName { get { return "Scooty- Name"; } set { VehicleName = value; } } }
class DarkHorseBike : IVehicle { public string VehicleName { get { return "DarkHorse Bike- Name"; } set { VehicleName = value; } } }

class Program
{
    static void Main(string[] args)
    {
        IVehicleFactory honda = new HondaFactory(); //1
        RegularBike hondaRegularBike = (RegularBike)honda.CreateSingleVehicle("Regular"); //2
        SportsBike hondaSportsBike = (SportsBike)honda.CreateSingleVehicle("Sports");
        Console.WriteLine("******* Honda **********"+hondaRegularBike.VehicleName+ hondaSportsBike.VehicleName);

        IVehicleFactory hero = new HeroFactory();
        DarkHorseBike heroDarkHorseBike = (DarkHorseBike)hero.CreateSingleVehicle("DarkHorse");
        SportsBike heroSportsBike = (SportsBike)hero.CreateSingleVehicle("Sports");
        Scooty heroScooty = (Scooty)hero.CreateSingleVehicle("Scooty");
        Console.WriteLine("******* Hero **********"+heroDarkHorseBike.VehicleName + heroScooty.VehicleName+ heroSportsBike.VehicleName);

        Console.ReadKey();
    }
}

Points importants: 1. Exigence: Honda créerait "Regular", "Sports" mais Hero créerait "DarkHorse", "Sports" et "Scooty". 2. pourquoi deux interfaces? Un pour le type de fabricant (IVehicleFactory) et un autre pour l'usine de produits (IVehicle); l'autre manière de comprendre 2 interfaces est l'usine abstraite est tout au sujet de créer des objets liés 2. Le hic est le retour des enfants de l'IVehicleFactory et IVehicle (au lieu du béton en usine); je reçois donc la variable parent (IVehicle); puis je crée un type concret réel en appelant CreateSingleVehicle puis en moulant l'objet parent en objet enfant réel. Que se passerait-il si je le faisais RegularBike heroRegularBike = (RegularBike)hero.CreateSingleVehicle("Regular");; vous obtiendrez ApplicationException et c'est pourquoi nous avons besoin d'une fabrique abstraite générique que j'expliquerais si nécessaire.

Saurabh
la source
1

Abstract Factory : Une usine d'usines; une usine qui regroupe les usines individuelles mais liées / dépendantes sans spécifier leurs classes concrètes. Exemple d'usine abstraite

Factory : il fournit un moyen de déléguer la logique d'instanciation aux classes enfants. Exemple de modèle d'usine

Atul Jain
la source
0

Je préférerais à tout moment Abstract Factory à Factory Method. À partir de l'exemple de Tom Dalling (grande explication btw) ci-dessus, nous pouvons voir que Abstract Factory est plus composable en ce que tout ce que nous devons faire est de passer une autre usine au constructeur (injection de dépendance de constructeur utilisée ici). Mais Factory Method nous oblige à introduire une nouvelle classe (plus de choses à gérer) et à utiliser le sous-classement. Préférez toujours la composition à l'héritage.

he9lin
la source
0

permettez-moi de le dire avec précision. la plupart des réponses ont déjà été expliquées et ont également fourni des diagrammes et des exemples. donc ma réponse serait juste un paquebot. mes propres mots: - «le modèle d'usine abstrait ajoute la couche abstraite sur plusieurs implémentations de méthodes d'usine. signifie que l'usine abstraite contient ou composite un ou plusieurs modèles de méthode d'usine »

Roi
la source
Ce n'est pas correct. C'est l'idée fausse bien trop répandue qu'Abstract Factory n'est rien de plus qu'une usine d'usines.
jaco0646
0

Un grand nombre des réponses ci-dessus ne fournissent pas de comparaisons de code entre le modèle Abstract Factory et Factory Method. Voici ma tentative de l'expliquer via Java. J'espère que cela aide quelqu'un qui a besoin d'une explication simple.

Comme GoF le dit avec justesse: Abstract Factory fournit une interface pour créer des familles d'objets liés ou dépendants sans spécifier leurs classes concrètes.

        public class Client {
            public static void main(String[] args) {
               ZooFactory zooFactory = new HerbivoreZooFactory();       
               Animal animal1 = zooFactory.animal1();
               Animal animal2 = zooFactory.animal2();
               animal1.sound();
               animal2.sound();

               System.out.println();

               AnimalFactory animalFactory = new CowAnimalFactory();
               Animal animal = animalFactory.createAnimal();
               animal.sound();
            }
        }

        public interface Animal {
            public void sound();
        }

        public class Cow implements Animal {

            @Override
            public void sound() {
                System.out.println("Cow moos");
            }

        }

        public class Deer implements Animal {

            @Override
            public void sound() {
                System.out.println("Deer grunts");
            }

        }

        public class Hyena implements Animal {

            @Override
            public void sound() {
                System.out.println("Hyena.java");
            }

        }

        public class Lion implements Animal {

            @Override
            public void sound() {
                System.out.println("Lion roars");
            }

        }

        public interface ZooFactory {
            Animal animal1();

            Animal animal2();
        }

        public class CarnivoreZooFactory implements ZooFactory {

            @Override
            public Animal animal1() {
                return new Lion();
            }

            @Override
            public Animal animal2() {
                return new Hyena();
            }

        }

        public class HerbivoreZooFactory implements ZooFactory{

            @Override
            public Animal animal1() {
                return new Cow();
            }

            @Override
            public Animal animal2() {
                return new Deer();
            }

        }

        public interface AnimalFactory {
            public Animal createAnimal();
        }

        public class CowAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Cow();
            }

        }

        public class DeerAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Deer();
            }

        }

        public class HyenaAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Hyena();
            }

        }

        public class LionAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Lion();
            }

        }
Jatin Shashoo
la source
Ce n'est pas correct. Ce code met en œuvre l'idée fausse bien trop courante selon laquelle Abstract Factory n'est rien de plus qu'une usine d'usines.
jaco0646
1
@ jaco0646 Je crois que dans le modèle de méthode d'usine, l'accent est mis sur la sortie d'un seul produit concret de FactoryImpl. Alors que dans le modèle d'usine abstrait, les FactoryImpls sont responsables de la fourniture de plusieurs ConcreteProducts similaires / liés, pour lesquels l'interface Factory fournit un contrat. ZooFactory n'est donc pas du tout une usine d'usines, comme vous le dites, mais juste une interface dont les implants fournissent des produits concrets qui sont liés les uns aux autres. N'hésitez pas à corriger ma compréhension si vous n'êtes pas d'accord.
Jatin Shashoo
Dans la méthode d'usine, l'accent est mis sur l'héritage via la sous-classification, car la méthode d'usine est une spécialisation du modèle de méthode de modèle. La réponse la plus votée ci-dessus montre un exemple de code décent.
jaco0646
@ jaco0646 1. Cela signifie-t-il que dans l'exemple ci-dessus, au lieu d'utiliser des interfaces pour AnimalFactory et de fournir ses implémentations, j'aurais dû utiliser une classe et substituer la méthode createAnimal () dans ses sous-classes: CowAnimalFactory, LionAnimalFactory, etc. ?? 2. Aussi, que pensez-vous de l'exemple montré pour ZooFactory ??
Jatin Shashoo
À la première question: oui. À la seconde, j'ai ajouté ma propre réponse à ce fil plutôt que de continuer à critiquer chaque réponse individuelle.
jaco0646