web-dev-qa-db-fra.com

Modèles de conception: Méthode abstraite vs usine

_ {Remarque: les questions se trouvent à la fin du message.} _

J'ai lu les autres threads stackoverflow concernant Abstract Factory vs Factory Method. Je comprends l'intention de chaque modèle. Cependant, je ne suis pas clair sur la définition.

La méthode d'usine définit une interface pour créer un objet, mais permet les sous-classes décident lesquelles de ces personnes instancier. Une méthode d'usine permet les classes reportent l'instanciation à sous-classes.

En revanche, une fabrique abstraite fournit une interface pour créer familles de personnes apparentées ou à charge objets sans spécifier leur cours concrets.

- John Feminella

Abstract Factory est très similaire à la méthode Factory. J'ai dessiné quelques classes UML pour illustrer mon propos. 

Remarque: 

  • Le diagramme provient de (www.yuml.com} _ afin qu’ils ne soient pas parfaitement orientés. Mais c'est un service gratuit :).
  • Les diagrammes peuvent ne pas être parfaits. J'apprends encore les modèles de conception GoF.

Méthode d'usine:

Factory Method

Fabrique abstraite (1 seul membre):

Abstract Factory (only 1 member)

Fabrique abstraite (plus de membres):

alt text

Des questions:

  1. Si Abstract Factory n'a qu'un seul créateur et un seul produit, reste-t-il toujours le motif Abstract Factory? _ {(une interface pour créer des familles)} _
  2. Le créateur concret Factory Method peut-il être créé à partir d'une interface ou doit-il appartenir à une classe? (les classes reportent les instanciations aux sous-classes)}
  3. Si Abstract Factory ne peut avoir qu’un créateur et un produit, c’est la seule différence entre la méthode Abstract Factory et la méthode Factory selon laquelle le créateur de la première est une interface et le créateur de la dernière est Classe?
139
user295190

J'espère que cela t'aides. Il décrit les différents types d'usines. J'ai utilisé Head First Design Patterns comme référence. J'ai utilisé yuml.me à diagramme.

Usine statique

Est une classe avec une méthode statique pour produire divers sous-types de produit.

Static Factory

Simple Factory

Est une classe pouvant produire divers sous-types de produits. (Cela vaut mieux que l'usine statique. Lorsque de nouveaux types sont ajoutés, la classe de produits de base n'a pas besoin d'être modifiée, mais uniquement la classe d'usine simple.)

Simple Factoryt

Méthode d'usine

Contient une méthode pour produire un type de produit associé à ce type. (C'est mieux qu'une Simple Factory car le type est différé dans une sous-classe.)

Factory Method

Fabrique abstraite

Produit une famille de types liés. Elle est sensiblement différente d’une méthode d’usine puisqu’elle produit plus d’une méthode. (Ceci est compliqué, reportez-vous au diagramme suivant pour un meilleur exemple de la vie réelle).

Abstract Factory

Exemple du .NET Framework

DbFactoriesProvider est une usine simple car elle ne comporte aucun sous-type. DbFactoryProvider est une fabrique abstraite car il peut créer divers objets de base de données connexes, tels que des objets de connexion et de commande.

Abstract Factory From .NET Framework

130
user295190

Les deux modèles sont certainement liés!

La différence entre les modèles est généralement dans l'intention.

La intention de la méthode Factory est "Définissez une interface pour la création d'un objet, mais laissez les sous-classes décider de la classe à instancier. La méthode Factory permet à une classe de différer l'instanciation en sous-classes."

La intention de Abstract Factory est "Fournit une interface pour la création de familles d'objets liés ou dépendants sans spécifier leurs classes concrètes."

Fondée uniquement sur ces déclarations d'intention (citées dans GoF), je dirais que Factory Method est en quelque sorte une "dégénérée" Abstract Factory avec une famille de l'un.

Leur mise en œuvre a généralement tendance à différer, car Factory Method est beaucoup plus simple que Abstract Factory.

Ils sont cependant également liés à la mise en œuvre. Comme indiqué dans le livre GoF,

AbstractFactory ne déclare qu'une interface pour la création de produits. C'est aux sous-classes ConcreteProduct de les créer. Le moyen le plus courant consiste à définir une méthode de fabrication pour chaque produit.

Ce c2 wiki a également une discussion intéressante sur ce sujet.

76
Don Roby

Il semble que la liste des (excellentes) questions du PO ait été ignorée. Les réponses actuelles offrent simplement des définitions remaniées. Je vais donc essayer de répondre aux questions initiales de manière concise.

  1. Si la fabrique abstraite n'a qu'un créateur et un produit, s'agit-il toujours du motif fabrique abstraite? (une interface pour créer des familles)

Non. Une usine abstraite doit créer plusieurs produits pour constituer une "famille de produits connexes". L'exemple canonique de GoF crée ScrollBar() et Window(). L'avantage (et l'objectif) est que Abstract Factory peut appliquer un thème commun à ses multiples produits.

  1. Le créateur concret Méthode d'usine _ peut-il être créé à partir d'une interface ou doit-il appartenir à une classe? (les classes reportent les instanciations aux sous-classes)

Tout d’abord, il faut noter que ni Java ni C # n’existaient lorsque le GoF a écrit son livre. L'utilisation par le GoF du terme interface n'est pas liée aux types d'interface introduits par des langues particulières. Par conséquent, le créateur concret peut être créé à partir de n'importe quelle API. Le point important du modèle est que l'API utilise sa propre méthode Factory. Par conséquent, une interface avec une seule méthode ne peut pas être une méthode Factory, pas plus qu'elle ne peut être une usine abstraite.

  1. Si l’abstrait Factory ne peut avoir qu’un créateur et un produit, c’est la seule différence entre Abstrait Factory et le Méthode Factory que le créateur pour le premier est une interface et le créateur pour le second est une classe?

Cette question n'est plus valide si vous suivez les réponses ci-dessus. Toutefois, si vous pensez que la seule différence entre Abstract Factory et Factory Method est le nombre de produits créés, réfléchissez à la façon dont un client utilise chacun de ces modèles. Une Abstract Factory est généralement injectée dans son client et appelée via une composition/délégation. Une méthode d'usine doit être héritée. Tout revient donc à l’ancien débat sur la composition et l’héritage.

Mais ces réponses ont soulevé une quatrième question!

  1. Depuis, une interface avec une seule méthode ne peut pas être une méthode de la fabrique pas plus qu'elle ne peut être une fabrique abstraite, comment on appelle un. interface de création avec une seule méthode?

Si la méthode est statique, on l'appelle communément une fabrique statique. Si la méthode est non statique, on l'appelle généralement une Simple Factory. Aucun de ceux-ci n'est un modèle GoF, mais dans la pratique, ils sont beaucoup plus couramment utilisés!

13
jaco0646

À mon avis, la légère différence entre les deux modèles réside dans la applicabilité , et donc, comme déjà dit, dans le Intention

Récapitulons les définitions (toutes deux de Wikipedia). 

Fabrique abstraite

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

Méthode d'usine

Définissez une interface pour créer un objet , mais laissez les classes qui implémentent l'interface décident quelle classe instancier . La méthode Factory permet à une classe de différer l'instanciation en sous-classes.

Les deux modèles permettent de dissocier les objets utilisateur de la création des instances nécessaires (découplage au moment de l'exécution), ce qui constitue l'aspect commun. Les deux modèles permettent de créer une hiérarchie d'usines en fonction de besoins spécifiques, ce qui constitue un autre aspect commun. 

Abstract Factory permet de créer plusieurs types d'instances différents dans une sous-classe et de préciser le comportement des créations dans ses différentes sous-classes. normalement, la méthode Factory déclare la création d'un seul type d'objet pouvant être particularisé selon le mécanisme de sous-classification. C'est la différence.

En résumant. Supposons que Product définit la super-classe des objets en création et que ProductA et ProductB sont deux sous-classes différentes. Par conséquent, la méthode Abstract Factory aura deux méthodes, createProductA () et createProductB () qui seront particularisées (en termes d’étapes de création) dans ses sous-classes spécifiques: les sous-classes d’usine particularisent les étapes de création pour les deux classes d'objets définies en cours de création. 

Selon l'exemple ci-dessus, la méthode Factory sera mise en œuvre différemment, résumant la création de ProductA et de ProductB dans autant d'usines (une méthode par usine), et la spécialisation supplémentaire des étapes creation sera déléguée à la hiérarchie. comme il est construit.

4
Paolo Maresca

Si j'ai créé un résumé (référencé via une interface ou une classe de base abstraite) Classe Factory qui crée des objets avec une seule méthode pour créer des objets, il s'agirait alors de Méthode Factory .

Si la fabrique abstraite avait plus d'une méthode pour créer des objets, il s'agirait d'un Abstract Factory .

Supposons que je crée un gestionnaire qui gérera les besoins en méthodes d'action pour un contrôleur MVC . S'il avait une méthode, par exemple, pour créer les objets de moteur utilisés pour créer les modèles de vue, il s'agirait d'une méthode d'usine pattern . D'autre part, s'il avait deux méthodes: une pour créer des moteurs de modèle de vue, et un autre pour créer des moteurs de modèle d'action (ou ce que vous voulez appeler le modèle que la méthode d'action contient de consommateurs), ce serait alors: une usine abstraite.

public ActionResult DoSomething(SpecificActionModel model)
{
    var actionModelEngine = manager.GetActionModelEngine<SpecificActionModel>();
    actionModelEngine.Execute(SpecificActionModelEnum.Value);

    var viewModelEngine = manager.GetViewModelEngine<SpecificViewModel>();
    return View(viewModelEngine.GetViewModel(SpecificViewModelEnum.Value);
}
2

Même si cela fait de nombreuses années que des membres de StackOverflow ont été interrogés de la même manière sur cette question dans d'autres publications (la plus ancienne datant de 2009), je ne pouvais toujours pas trouver la réponse que je voulais.


J'ai donc passé quelques heures à effectuer des recherches sur le Web, en passant en revue les exemples, et j'en suis venu à cette conclusion: les principales différences entre Abstract Factory et Factory Method sont

  • L'intention: cohérence ou "look-and-feel": l'intention de Abstract Factory est de regrouper une famille d'objets ayant le même style (ex.: Mêmes widgets d'interface utilisateur ayant l'apparence et la convivialité, parties de voiture du même style, objets de même système d’exploitation, etc.) De nombreux exemples de Abstract Factory mentionnent la phrase clé "le même aspect".
  • Objets formant un objet groupe plus grand: Abstract Factory crée une famille d'objets formant un objet groupe plus grand, pas un seul objet.
  • Plus tard, ajouter un nouveau style: Si nous continuions à utiliser la méthode Factory et tentions d'ajouter un nouveau jeu de style à l'infrastructure existante, cela serait douloureux. Avec Abstract Factory, il suffit de créer une nouvelle usine de béton qui implémente la classe d’usines abstraites.

Les contre exemples seraient 

  • Pièce de voiture de sport utilisée dans une berline. Cette incohérence peut entraîner des accidents.
  • Un bouton de style Windows dans différents widgets d'interface graphique du système d'exploitation. Cela ne va pas casser n'importe quoi mais blesser l'expérience utilisateur pour certaines personnes, comme moi.
  • Plus tard, nous découvrons que notre logiciel doit être exécuté lors de la prochaine mise à niveau du système d'exploitation, ce qui nécessite un ensemble différent d'objets système compatibles, tout en préservant la compatibilité ascendante du logiciel.

Par conséquent, lorsqu'un groupe d'objets final doit avoir le même style sans exception et que vous souhaitez masquer ce détail "conserver le même style", vous devez utiliser Abstract Factory.

1
Andrew Chong
/*
//Factory methods:

//1. Factory Method - Abstract Creator Class



#include <iostream>
#include <string.h>
using namespace std;

const std::string nineNintyCC = std::string("990CC");
const std::string thousandTwoHundredCC = std::string("1200CC");
const std::string ThousandFiveHundredCC = std::string("1500CC");
const std::string fiveThousandCC = std::string("5000CC");

// Product
class Engine
{
    public:
    virtual void packEngine() = 0;  
};

// Concrete products
// concrete product class one
class C990CCEngine: public Engine
{

    public:
    void packEngine()
    {
       cout << "Pack 990CC engine" << endl;   
    }
};

// concrete class Two
class C1200CCEngine: public Engine
{   public:
    void packEngine()
    {
        cout << "pack 1200CC engine" << endl;
    }

};

// Concrete class Three
class C1500CCEngine: public Engine
{
    public:
    void packEngine()
    {
        cout << "Pack 1500CC engine" << endl;
    }

};


// Car Factory:
class CarFactory{
    public:

    virtual Engine* createEngine(const std::string& type) = 0;
};
class Factory: public CarFactory
{
    public:
     Engine *createEngine(const std::string& type)
     {

          if(0 == nineNintyCC.compare(type))
          {    
             return new C990CCEngine;
          }
          else if(0 == thousandTwoHundredCC.compare(type))
          {
             return new C1200CCEngine;
          }
          else if(0 == ThousandFiveHundredCC.compare(type))
          {
             return new C1500CCEngine;
          } 
          else
           {
                 cout << "Invalid factory input" << endl;
             return NULL;
           }
           return NULL;
     }
};

int main()
{

    CarFactory* ptr = new Factory;
    Engine*pEngine =  ptr->createEngine(nineNintyCC);
    if(pEngine)
    {
        pEngine->packEngine();
        delete pEngine;
    }
    else
    {
        cout << "No engine exists of your type in our factory" << endl;
    }
    pEngine =  ptr->createEngine(ThousandFiveHundredCC);
    if(pEngine)
    {
        pEngine->packEngine();
        delete pEngine;
    }
    else
    {
        cout << "No engine exists of your type in our factory" << endl;
    }
    pEngine =  ptr->createEngine(thousandTwoHundredCC);
    if(pEngine)
    {
        pEngine->packEngine();
        delete pEngine;
    }
    else
    {
        cout << "No engine exists of your type in our factory" << endl;
    }
    pEngine = ptr-> createEngine(fiveThousandCC);
    if(pEngine)
    {
        pEngine->packEngine();
        delete pEngine;
    }
    else
    {
        cout << "No engine exists of your type in our factory" << endl;
    }
    return 0;
}

*/
/*
//
// interface product
#include <iostream>
#include <string>
using namespace std;

class Engine
{
 public:
 virtual void EngineType() = 0;

};

// concrte product
class AltoEngine: public Engine
{
  public:
  void EngineType()
  {
      cout << "Alto Engine" << endl;
  }
};

//Concrte product
class SwiftEngine : public Engine
{
    public:
    void EngineType()
    {
        cout << "Swift Engine" << endl;    
    }
};

class Body
{
   public:
    virtual void bodyType() = 0;

};

class AltoBody: public Body
{
  public:  
    virtual void bodyType()
    {
        cout << "Alto Car Body" << endl;
    }
};

class SwiftBody : public Body
{
    public:
    void bodyType()
    {
        cout << "SwiftCar Body" << endl;
    }

};


class CarFactory
{
   public:
   virtual Engine* createEngineProduct() = 0;
   virtual Body*   createBodyPoduct() = 0;
};
class AltoCarFactory: public CarFactory
{
    public:
    Engine * createEngineProduct()
    {
        return new AltoEngine;
    }
    Body* createBodyPoduct()
    {
        return new AltoBody;
    }

};

class SwiftCarFactory: public CarFactory
{
    public:
    Engine * createEngineProduct()
    {
        return new SwiftEngine;
    }
    Body* createBodyPoduct()
    {
        return new SwiftBody;
    }

};

int main()
{

    CarFactory* pAltoFactory = new AltoCarFactory;
    Engine* pAltoEngine = pAltoFactory->createEngineProduct();
    pAltoEngine->EngineType();
    Body* pAltoBody = pAltoFactory->createBodyPoduct();
    pAltoBody->bodyType();



    CarFactory* pSwiftFactory = NULL;
    pSwiftFactory = new SwiftCarFactory;
    Engine* pSwiftEngine = pSwiftFactory->createEngineProduct();
    pSwiftEngine->EngineType();
    Body* pSwfitBody = pSwiftFactory->createBodyPoduct();
    pSwfitBody->bodyType();
    delete pAltoBody;
    delete pAltoFactory;
    delete pSwfitBody;
    delete pSwiftFactory;
    return 0;
}
*/

/*

// One more Factory example;

#include <iostream>
#include <string>
using namespace std;

const std::string maruthi = std::string("Maruthi");
const std::string fiat = std::string("Fiat");
const std::string renault = std::string("Renault");
// Interface
class CarEngine
{
 public:
    virtual void engineType() = 0;
};

// Concrete class
class FiatEngine: public CarEngine
{
  public:
  void engineType()
  {
      cout << "Fait Engine Engine" << endl;
  }

};
// ConcreteClass
class RenaultEngine : public CarEngine
{
    public:
    void engineType()
    {
        cout << "Renault Engine" << endl;
    }

};
// Concrete class
class MaruthiEngine : public CarEngine
{
    public:
    void engineType()
    {
        cout << "Maruthi Engine" << endl;
    }
};


// Factory
class CarFactory
{
    public:
    virtual CarEngine* createFactory(const std::string&) = 0;
};

// EngineFactory
class CarEngineFactory : public CarFactory
{
     public:
     CarEngine* createFactory(const std::string&  type)
     {
          if(0 == maruthi.compare(type))
          {
              return new MaruthiEngine;

          }
          else if(0 == fiat.compare(type))
          {
              return  new FiatEngine;
          }
          else if(0 == renault.compare(type))
          {
              return new RenaultEngine;
          }
          else
          {
              cout << "Invalid Engine type" << endl;
              return NULL;
          }
     }

  };

int main()
{
    CarFactory* pCarFactory = new CarEngineFactory;
    CarEngine* pMaruthiCarEngine = pCarFactory->createFactory(maruthi);
    pMaruthiCarEngine->engineType();

    CarEngine* pFiatCarEngine = pCarFactory->createFactory(fiat);
    pFiatCarEngine->engineType();


    CarEngine* pRenaultCarEngine = pCarFactory->createFactory(renault);
    pRenaultCarEngine->engineType();

    return 0;
}


*/


/*

// One more Factory example;

#include <iostream>
#include <string>
using namespace std;

const std::string maruthi = std::string("Maruthi");
const std::string fiat = std::string("Fiat");
const std::string renault = std::string("Renault");


// Interface
class CarEngine
{
 public:
    virtual void engineType() = 0;
};

// Concrete class
class FiatEngine: public CarEngine
{
  public:
  void engineType()
  {
      cout << "Fait Car Engine" << endl;
  }

};

// ConcreteClass
class RenaultEngine : public CarEngine
{
    public:
    void engineType()
    {
        cout << "Renault Car Engine" << endl;
    }

};

// Concrete class
class MaruthiEngine : public CarEngine
{
    public:
    void engineType()
    {
        cout << "Maruthi Car Engine" << endl;
    }
};

// Interface
class CarBody
{
 public:
    virtual void bodyType() = 0;
};

// Concrete class
class FiatBody: public CarBody
{
  public:
  void bodyType()
  {
      cout << "Fait car Body" << endl;
  }

};

// ConcreteClass
class RenaultBody : public CarBody
{
    public:
    void bodyType()
    {
        cout << "Renault Body" << endl;
    }

};

// Concrete class
class MaruthiBody : public CarBody
{
    public:
    void bodyType()
    {
        cout << "Maruthi body" << endl;
    }
};


// Factory
class CarFactory
{
    public:
    virtual CarEngine* createCarEngineProduct() = 0;
    virtual CarBody* createCarBodyProduct() = 0;
};

// FiatFactory
class FaitCarFactory : public CarFactory
{
     public:
     CarEngine* createCarEngineProduct()
     {
        return new FiatEngine; 
     }
     CarBody* createCarBodyProduct()
     {
         return new FiatBody;
     }
};

// Maruthi Factory
class MaruthiCarFactory : public CarFactory
{
     public:
     CarEngine* createCarEngineProduct()
     {
         return new MaruthiEngine;
     }
     CarBody* createCarBodyProduct()
     {
         return new MaruthiBody;
     }

};

// Renault Factory
class RenaultCarFactory : public CarFactory
{
     public:
    CarEngine* createCarEngineProduct()
    {
        return new RenaultEngine;
    }

    CarBody* createCarBodyProduct()
    {
        return new RenaultBody;
    }

};


int main()
{

   // Fiat Factory
   CarFactory* pFiatCarFactory = new FaitCarFactory;
   CarEngine* pFiatEngine = pFiatCarFactory->createCarEngineProduct();
   CarBody*  pFiatBody = pFiatCarFactory->createCarBodyProduct();
   pFiatEngine->engineType();
   pFiatBody->bodyType();

   // Renault Car Factory
    return 0;
}

*/
0
user1573259

Autant que je sache ce que cela signifie o Définitions de la fabrique abstraite et de la méthode fabrique, la première est implémentée dans un contexte statique et fournit un objet basé sur des paramètres d'entrée.

La seconde utilise l’objet déjà créé (la famille) qui implémente l’interface de la méthode factory. La méthode fabrique ensuite une instance spécifique liée à l'objet d'origine, peu importe de quoi il s'agit.

Cela conduit donc généralement à utiliser les deux modèles ensemble, dans la première étape, vous créez un objet général qui décrit une famille d’objets apparentés. Elle est appelée par la méthode statique getInstance (méthode "mon nom de famille"). L'implémentation de cette méthode getInstance détermine quel objet familial sera créé.

Ensuite, j'appelle la méthode createProduct () sur un objet de famille nouvellement créé et, selon l'objet de famille dépendant, le nouveau produit est renvoyé.

Il semble que ces modèles coopèrent avec chacun.

En d'autres termes, Abstract Factory se concentre sur "QUOI" sera créé et la méthode Factory "COMMENT" elle sera créée.

0
Jan Stanicek

Le modèle de méthode d'usine est un modèle de création qui traite de la création d'objets sans afficher la classe exacte d'objet en cours de création. Ce modèle de conception permet essentiellement à une classe de différer l'instanciation en sous-classes.

Le modèle Abstract Factory sert à encapsuler un groupe d’usines individuelles sans exposer les classes concrètes. Dans ce modèle, une interface générique d'une classe de fabrique abstraite est utilisée pour créer l'objet concret requis séparant les détails de la mise en oeuvre des objets de leur utilisation et de leur composition. Ce modèle de conception est largement utilisé dans les applications d'interface graphique où des types similaires de composants d'interface graphique doivent être créés.

en cherchant sur google, je suis arrivé à la suite d'un blog qui expliquait les deux motifs de manière brillante. jetez un oeil sur ces

http://simpletechtalks.com/factory-design-pattern/

http://simpletechtalks.com/abstract-factory-design-pattern/

0
Neo

Tout ce que vous devez retenir, c’est qu’une fabrique abstraite est une fabrique pouvant renvoyer plusieurs usines . Donc si vous avez une AnimalSpeciesFactory, elle peut retourner des usines comme ceci:

Mamalfactory, BirdFactory, Fishfactory, ReptileFactory. Maintenant que vous n’avez plus qu’une usine issue de AnimalSpeciesFactory, ils utilisent le modèle d’usine pour créer des objets spécifiques. Par exemple, imaginez que vous avez obtenu une ReptileFactory de cette AnimalFactory, puis vous pouvez proposer de créer des objets de reptiles tels que: Objets serpents, tortues, lézards. 

0
j2emanue