Patrones de diseño: Fábrica abstracta vs Método de fábrica

141

Nota: las preguntas se encuentran al final de la publicación.

He leído los otros hilos de stackoverflow con respecto a Abstract Factory vs Factory Method . Entiendo la intención de cada patrón. Sin embargo, no tengo clara la definición.

El Método de Fábrica define una interfaz para crear un objeto, pero permite que las subclases decidan cuáles instanciar. Un método de fábrica permite que las clases difieran la creación de instancias en subclases.

Por el contrario, una Fábrica abstracta proporciona una interfaz para crear familias de objetos relacionados o dependientes sin especificar sus clases concretas.

- John Feminella

El Abstract Factory es muy similar al método de fábrica . He dibujado algunas clases de UML para ilustrar mi punto.

Nota:

  • El diagrama es de www.yuml.com, por lo que no están perfectamente orientados. Pero es un servicio gratuito :).
  • Los diagramas pueden no ser perfectos. Todavía estoy aprendiendo los patrones de diseño de GoF .

Método de fábrica

Método de la fábrica

Abstract Factory (solo 1 miembro):

Abstract Factory (solo 1 miembro)

Fábrica abstracta (más miembros):

texto alternativo

Preguntas:

  1. Si Abstract Factory solo tiene un creador y un producto, ¿sigue siendo el patrón Abstract Factory ? (una interfaz para crear familias)
  2. ¿Se puede crear el creador concreto Factory Method desde una interfaz o tiene que ser de una clase? (las clases difieren las instancias a subclases)
  3. Si Abstract Factory puede tener solo un creador y un producto, ¿es la única diferencia entre Abstract Factory y Factory Method que el creador para el primero es una Interfaz y el creador para el segundo es una Clase?
Armandino
fuente
1
Nota: Cuando me refiero a la interfaz, estaba pensando más en los términos de una interfaz Java (clase abstracta con métodos virtuales abstractos). No dude en aclarar si existe una diferencia entre Abstract Factory y Factory Method en diferentes idiomas.
Una diferencia básica aquí: stackoverflow.com/questions/1001767 , aunque no es tan específico como lo estás preguntando ..
nawfal

Respuestas:

134

Espero que esto ayude. Describe los diversos tipos de fábricas. Usé Head First Design Patterns como mi referencia. Solía yuml.me a diagrama.

Fábrica estática

Es una clase con un método estático para producir varios subtipos de producto.

Fábrica estática

Fábrica simple

Es una clase que puede producir varios subtipos de Producto. (Es mejor que la fábrica estática. Cuando se agregan nuevos tipos, la clase de producto base no necesita cambiarse solo la clase de fábrica simple)

Factoryt simple

Método de la fábrica

Contiene un método para producir un tipo de producto relacionado con su tipo. (Es mejor que Simple Factory porque el tipo se difiere a una subclase).

Método de la fábrica

Fábrica abstracta

Produce una familia de tipos que están relacionados. Es notablemente diferente a un Método de Fábrica ya que tiene más de un método de tipos que produce. (Esto es complicado; consulte el siguiente diagrama para obtener un mejor ejemplo de la vida real).

Fábrica abstracta

Ejemplo de .NET Framework

DbFactoriesProvider es una Fábrica simple ya que no tiene subtipos. DbFactoryProvider es una fábrica abstracta, ya que puede crear varios objetos de base de datos relacionados, como objetos de conexión y comando.

Fábrica abstracta de .NET Framework

1valdis
fuente
¿La diferencia entre Static Factory y Simple Factory es que el método CreateProduct se encuentra dentro de una clase diferente?
Peter O'Callaghan
44
¿No sería más claro si en el caso del Método de Fábrica, solo hubiera Product(como resumen), y luego Product1y Product2, como hijos? Eso ayudaría al punto de que Factory Method se trata solo de crear un producto, mientras que Abstract Factory es más o menos un grupo de Factory Method reunidos en familias.
lllllll
79

¡Los dos patrones están ciertamente relacionados!

La diferencia entre patrones generalmente está en la intención.

La intención del Método Factory es "Definir una interfaz para crear un objeto, pero dejar que las subclases decidan qué clase instanciar. El Método Factory permite que una clase difiera la instanciación a subclases".

La intención de Abstract Factory es "Proporcionar una interfaz para crear familias de objetos relacionados o dependientes sin especificar sus clases concretas".

Basándome exclusivamente en estas declaraciones de intenciones (citadas por GoF), diría que, de hecho , el Método Factory es, en cierto sentido, una Fábrica abstracta "degenerada" con una familia de uno.

En general, tienden a diferir en la implementación, ya que Factory Method es mucho más simple que Abstract Factory .

Sin embargo, también están relacionados en la implementación. Como se señala en el libro de GoF,

AbstractFactory solo declara una interfaz para crear productos. Depende de las subclases de ConcreteProduct crearlas realmente. La forma más común de hacer esto es definir un método de fábrica para cada producto.

Este wiki de c2 también tiene una discusión interesante sobre este tema.

Don Roby
fuente
77
No entiendo ni el comentario ni el voto negativo. ¿Puedes elaborar?
Don Roby
Bueno, las respuestas me parecen retóricas ... No hay un verdadero ejemplo concisa ... demasiado amplio ...
Novalis
14

Parece que la lista de preguntas (excelentes) del OP ha sido ignorada. Las respuestas actuales simplemente ofrecen definiciones repetidas. Así que intentaré abordar las preguntas originales de manera concisa.

  1. Si Abstract Factory solo tiene un creador y un producto, ¿sigue siendo el patrón Abstract Factory ? (una interfaz para crear familias)

No se . Una Fábrica abstracta debe crear más de un producto para formar una "familia de productos relacionados". El ejemplo canónico de GoF crea ScrollBar()y Window(). La ventaja (y el propósito) es que Abstract Factory puede imponer un tema común en sus múltiples productos.

  1. ¿Se puede crear el creador concreto Factory Method desde una interfaz o tiene que ser de una clase? (las clases difieren las instancias a subclases)

Primero, debemos tener en cuenta que ni Java ni C # existían cuando el GoF escribió su libro. El uso de GoF del término interfaz no está relacionado con los tipos de interfaz introducidos por idiomas particulares. Por lo tanto, el creador concreto se puede crear desde cualquier API. El punto importante en el patrón es que la API consume su propio Método de Fábrica, por lo que una interfaz con un solo método no puede ser un Método de Fábrica más de lo que puede ser una Fábrica Abstracta.

  1. Si Abstract Factory puede tener solo un creador y un producto, ¿es la única diferencia entre Abstract Factory y Factory Method que el creador para el primero es una Interfaz y el creador para el segundo es una Clase?

Esta pregunta ya no es válida, siguiendo las respuestas anteriores; sin embargo, si se queda pensando que la única diferencia entre Abstract Factory y Factory Method es la cantidad de productos creados, considere cómo un cliente consume cada uno de estos patrones. Una Fábrica abstracta generalmente se inyecta en su cliente y se invoca a través de composición / delegación. Un método de fábrica debe ser heredado. Por lo tanto, todo vuelve al antiguo debate de composición vs. herencia.

¡Pero estas respuestas han planteado una cuarta pregunta!

  1. Dado que una interfaz con un solo método no puede ser un Método de Fábrica más de lo que puede ser una Fábrica Abstracta , ¿cómo llamamos una interfaz de creación con un solo método?

Si el método es estático, comúnmente se llama Fábrica estática . Si el método no es estático, comúnmente se llama Fábrica simple . Ninguno de estos es un patrón GoF, ¡pero en la práctica se usan mucho más comúnmente!

jaco0646
fuente
1
Sobre composición versus herencia, siempre me pregunté: ¿no es posible también hacer composición con el patrón Método de fábrica? ¿Qué evitaría que uno componga o inyecte la fábrica de concreto adecuada en un cliente? ¿O ya es algo fuera del alcance del patrón?
georaldc
1
@georaldc, del GoF (página 107) " El Método Factory permite que una clase difiera la creación de instancias en subclases " . En otras palabras, el Método Factory utiliza la herencia por definición.
jaco0646
4

En mi opinión, la ligera diferencia entre los dos patrones reside en la aplicabilidad y, como ya se dijo, en la intención .

Recapitulemos las definiciones (ambas de Wikipedia).

Fábrica abstracta

Proporcione una interfaz para crear familias de objetos relacionados o dependientes sin especificar sus clases concretas.

Método de la fábrica

Defina una interfaz para crear un objeto , pero deje que las clases que implementan la interfaz decidan qué clase instanciar . El método Factory permite que una clase difiera la creación de instancias en subclases.

Ambos patrones permiten desacoplar los objetos de usuario de la creación de instancias necesarias (desacoplamiento en tiempo de ejecución), y este es el aspecto común. Ambos patrones permiten crear una jerarquía de fábricas de acuerdo con cualquier necesidad específica, y este es otro aspecto común.

Abstract Factory permite crear varios tipos diferentes de instancias en una subclase y particularizar el comportamiento de las creaciones en sus diferentes subclases; normalmente, el método Factory declara la creación de un solo tipo de objeto que se puede particularizar de acuerdo con el mecanismo de subclasificación. Esa es la diferencia.

Resumiendo Digamos que Product define la superclase de los objetos de creación, y que ProductA y ProductB son dos subclases diferentes. Por lo tanto, el método Abstract Factory tendrá dos métodos, createProductA () y createProductB () que se particularizarán (en términos de pasos de creación) en sus subclases específicas: las subclases de fábrica particularizan los pasos de creación para las dos clases definidas de objetos bajo creación.

Según el ejemplo anterior, el Método Factory se implementará de manera diferente, abstrayendo la creación de ProductA y ProductB en tantas fábricas (un método por Factory), y la especialización adicional de los pasos de creación se delegará a la jerarquía a medida que se construye. .

Paolo Maresca
fuente
2

Si creé una clase Factory abstraída (referenciada a través de una interfaz o clase base abstracta) que crea objetos que solo tienen un método para crear objetos, entonces sería un método Factory .

Si la Fábrica abstraída tuviera más de 1 método para crear objetos, entonces sería una Fábrica abstracta .

Digamos que creo un administrador que manejará las necesidades de los métodos de acción para un controlador MVC. Si tuviera un método, por ejemplo, para crear los objetos del motor que se utilizarán para crear modelos de vista, entonces sería un patrón de método de fábrica. Por otro lado, si tuviera dos métodos: uno para crear motores de modelos de vista y otro para crear motores de modelos de acción (o como quiera llamar al modelo que el método de acción contiene consumidores), entonces sería una fábrica abstracta.

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);
}
Christopher Stevenson
fuente
1

Aunque, han pasado muchos años desde que las personas de StackOverflow cuestionaron este problema de manera similar en otras publicaciones (la más antigua es de 2009), todavía no pude encontrar la respuesta que quería.


Así que hice algunas horas de investigación a través de la web, revisé los ejemplos, y llegué a esta conclusión, las principales diferencias de Abstract Factory con Factory Method son

  • La intención: coherencia o "look-and-feel" : la intención de Abstract Factory es agrupar una familia de objetos con el mismo estilo (por ejemplo, los mismos widgets de interfaz de usuario de look-and-feel, partes de automóviles del mismo estilo, objetos de un mismo sistema operativo, etc.) Muchos ejemplos de Abstract Factory mencionan la frase clave "la misma apariencia".
  • Objetos que forman un objeto de grupo más grande : Abstract Factory crea una familia de objetos que forman un objeto de grupo más grande, no un solo objeto.
  • Más adelante agregue un nuevo estilo : si continuamos usando el Método de Fábrica e intentamos agregar un nuevo conjunto de estilos a la infraestructura existente, sería doloroso. Con Abstract Factory, todo lo que tenemos que hacer es simplemente crear una nueva fábrica de concreto que implemente la clase de fábrica abstracta.

Los ejemplos contrarios serían

  • Una pieza de automóvil para automóvil deportivo utilizado en un sedán. Esta inconsistencia puede conducir a accidentes.
  • Un botón de estilo Windows en diferentes widgets de GUI del sistema operativo. No va a romper nada, pero perjudicará la experiencia del usuario para algunas personas, como yo.
  • Más tarde, descubrimos que nuestro software debe ejecutarse en la próxima actualización del sistema operativo, que necesita un conjunto diferente de objetos del sistema compatibles y mantener el software compatible con versiones anteriores.

Por lo tanto, cuando un grupo de objetos final debe tener el mismo estilo sin excepción de un objeto y desea ocultar este detalle de "mantener el mismo estilo", entonces debemos usar Abstract Factory.

Andrew Chong
fuente
0

Hasta donde entiendo el significado de las definiciones abstractas de fábrica y de método de fábrica, la primera se implementa en contexto estático y proporciona objetos basados ​​en parámetros de entrada.

El segundo usa un objeto ya creado (la familia) que implementa la interfaz del método de fábrica. El método de fábrica crea una instancia específica relacionada con el objeto original, sin importar cuál sea.

Por lo tanto, esto generalmente lleva a usar ambos patrones juntos, donde en el primer paso creas un objeto general que describe la familia de objetos relacionados. Se llama por el método estático método getInstance ("mi apellido"). La implementación de dicho método getInstance decide qué objeto familiar se creará.

Luego llamo al método createProduct () en un objeto familiar recién creado y, dependiendo del objeto familiar, se devolverá el nuevo producto.

Parece que estos patrones cooperan con cada uno.

En otras palabras, Abstract Factory se centra en "QUÉ" se creará y en el método Factory "CÓMO" se creará.

Jan Stanicek
fuente
0

Todo lo que debe recordar es que una fábrica abstracta es una fábrica que puede devolver varias fábricas . Entonces, si tuviera una AnimalSpeciesFactory, puede devolver fábricas como esta:

Mamalfactory, BirdFactory, Fishfactory, ReptileFactory. Ahora que tiene una única fábrica de AnimalSpeciesFactory, utilizan el patrón de fábrica para crear objetos específicos. Por ejemplo, imagina que obtuviste una ReptileFactory de esta AnimalFactory, entonces podrías ofrecer crear objetos de reptiles como: serpientes, tortugas, objetos de lagartos.

j2emanue
fuente
0
/*
//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;
}

*/
Chandrashekhar JP JCpuraTumkur
fuente
-1

El patrón de método de fábrica es un patrón de diseño de creación que trata de crear objetos sin mostrar la clase exacta de objeto que se está creando. Este patrón de diseño básicamente permite que una clase difiera la instanciación a subclases.

El patrón Abstract Factory sirve de encapsulación a un grupo de fábricas individuales sin exponer las clases concretas. En este modelo, se usa una interfaz genérica de una clase de fábrica abstracta para crear el objeto concreto requerido que separa los detalles de la implementación de los objetos de su uso y composición. Este patrón de diseño se usa ampliamente en aplicaciones GUI donde se necesita crear un tipo similar de componentes GUI.

Mientras buscaba en Google, encontré el siguiente blog que explicaba brillantemente ambos patrones de diseño. echar un vistazo a estos

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

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

Neo
fuente