¿Cuáles son las diferencias entre los patrones de diseño de Abstract Factory y Factory?

455

Sé que hay muchas publicaciones sobre las diferencias entre estos dos patrones, pero hay algunas cosas que no puedo encontrar.

Por lo que he estado leyendo, veo que el patrón del método de fábrica le permite definir cómo crear un solo producto concreto pero ocultando la implementación del cliente ya que verá un producto genérico. Mi primera pregunta es sobre la fábrica abstracta. ¿Es su función permitirle crear familias de objetos concretos (que pueden depender de la fábrica específica que use) en lugar de solo un objeto concreto? ¿La fábrica abstracta solo devuelve un objeto muy grande o muchos objetos dependiendo de los métodos que llame?

Mis dos preguntas finales son sobre una sola cita que no puedo entender completamente y que he visto en numerosos lugares:

Una diferencia entre los dos es que con el patrón Abstract Factory, una clase delega la responsabilidad de la instanciación de objetos a otro objeto a través de la composición, mientras que el patrón Factory Method usa la herencia y se basa en una subclase para manejar la instanciación de objetos deseada.

Tengo entendido que el patrón del método de fábrica tiene una interfaz Creator que hará que ConcreteCreator se encargue de saber qué ConcreteProduct creará. ¿Es esto lo que significa al usar la herencia para manejar la instanciación de objetos?

Ahora con respecto a esa cita, ¿cómo delega exactamente el patrón Abstract Factory la responsabilidad de la creación de instancias de objeto a otro objeto a través de la composición? ¿Qué significa esto? Parece que el patrón Abstract Factory también usa la herencia para hacer el proceso de construcción también en mis ojos, pero de nuevo todavía estoy aprendiendo sobre estos patrones.

Cualquier ayuda, especialmente con la última pregunta, sería muy apreciada.

Silverbolt
fuente
Ver "cómo se creó la instancia" desde el punto de vista del cliente, lo ayudaría a comprender la cita.
Karthik Bose
@nawfal, las respuestas en ese hilo son horribles.
jaco0646

Respuestas:

494

La diferencia entre los dos

La principal diferencia entre un "método de fábrica" ​​y una "fábrica abstracta" es que el método de fábrica es un método único, y una fábrica abstracta es un objeto. Creo que mucha gente confunde estos dos términos y comienza a usarlos indistintamente. Recuerdo que me costó encontrar exactamente cuál era la diferencia cuando los aprendí.

Debido a que el método de fábrica es solo un método, puede anularse en una subclase, de ahí la segunda mitad de su presupuesto:

... el patrón Método de fábrica utiliza la herencia y se basa en una subclase para manejar la instanciación de objeto deseada.

La cita supone que un objeto está llamando a su propio método de fábrica aquí. Por lo tanto, lo único que podría cambiar el valor de retorno sería una subclase.

La fábrica abstracta es un objeto que tiene múltiples métodos de fábrica. Mirando la primera mitad de su presupuesto:

... con el patrón Abstract Factory, una clase delega la responsabilidad de la instanciación de objetos a otro objeto a través de la composición ...

Lo que dicen es que hay un objeto A, que quiere hacer un objeto Foo. En lugar de hacer el objeto Foo en sí (por ejemplo, con un método de fábrica), obtendrá un objeto diferente (la fábrica abstracta) para crear el objeto Foo.

Ejemplos de código

Para mostrarle la diferencia, aquí hay un método de fábrica en uso:

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();
    }
}

Y aquí hay una fábrica abstracta en uso:

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
fuente
15
Esta es una gran explicación. Pero, ¿cuál es la parte más importante que queda sin respuesta, y es: cuándo usar uno y cuándo el otro patrón?
croraf
11
No estoy seguro de que esto sea correcto. Es bastante seguro que el Método de fábrica es un patrón de diseño que lleva el nombre de los métodos de fábrica, pero implica la estructura de clase y la herencia. No es un método único.
Aviv Cohn
2
Entonces, ¿es correcto decir: el método Factory puede ser un método en todas las clases regulares con diferentes propósitos. ¿Pero Abstract Factory es una clase / objeto utilizado por un cliente y es SOLO responsable de crear algunos productos en una familia?
Hieu Nguyen
¿Su uso de la palabra "Super" en "SuperFoo" solo significa un caso especial de Foo, o en realidad significa superclase? Como supuse, debe ser una subclase.
dahui
@dahui Sí, es una subclase. Lo he cambiado para SpecialFooque sea más claro.
Tom Dalling
125

Abstract factory crea una clase base con métodos abstractos que definen métodos para los objetos que deben crearse. Cada clase de fábrica que deriva la clase base puede crear su propia implementación de cada tipo de objeto.

ingrese la descripción de la imagen aquí

El método de fábrica es solo un método simple utilizado para crear objetos en una clase. Por lo general, se agrega en la raíz agregada (la Orderclase tiene un método llamado CreateOrderLine)

ingrese la descripción de la imagen aquí

Fábrica abstracta

En el siguiente ejemplo, diseñamos una interfaz para que podamos desacoplar la creación de colas de un sistema de mensajería y, por lo tanto, podamos crear implementaciones para diferentes sistemas de colas sin tener que cambiar la base del código.

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étodo de fábrica

El problema en los servidores HTTP es que siempre necesitamos una respuesta para cada solicitud.

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

    IHttpResponse CreateResponse(int httpStatusCode);
}

Sin el método de fábrica, los usuarios del servidor HTTP (es decir, los programadores) se verían obligados a usar clases específicas de implementación que anulen el propósito de la IHttpRequestinterfaz.

Por lo tanto, presentamos el método de fábrica para que la creación de la clase de respuesta también se abstraiga.

Resumen

La diferencia es que el propósito de la clase que contiene un método de fábrica no es crear objetos , mientras que una fábrica abstracta solo debe usarse para crear objetos.

Uno debe tener cuidado al usar métodos de fábrica ya que es fácil romper el LSP ( principio de sustitución de Liskov ) al crear objetos.

jgauffin
fuente
3
¿Por qué necesitamos un producto concreto?
Andrew S
6060
Porque nadie quiere invertir en ideas.
jgauffin
44
Abstract Factory debería crear más que solo Button()hacer una "familia de productos relacionados". Por ejemplo, el ejemplo canónico de GoF crea ScrollBar()y Window(). La ventaja es que Abstract Factory puede imponer un tema común en sus múltiples productos.
jaco0646
Jaco tiene razón. Tenga en cuenta que ambos diagramas UML son esencialmente iguales (además de que Abstract Factory UML está equivocado) En ambos casos, el cliente está llamando a un método de fábrica para crear un solo producto.
cobby
1
@ Andrew: Para responder a tu pregunta. Si no necesitamos tener diferentes productos concretos (clases) para la misma abstracción (interfaz), probablemente necesitemos el patrón generador y no el patrón de fábrica. (mejor tarde que nunca;))
jgauffin
95

La diferencia entre los patrones de diseño AbstractFactory y Factory es la siguiente:

  • El método de fábrica se usa para crear un solo producto, pero Abstract Factory se trata de crear familias de productos relacionados o dependientes.
  • El patrón Factory Method expone un método al cliente para crear el objeto, mientras que en el caso de Abstract Factory expone una familia de objetos relacionados que pueden consistir en estos métodos de Fábrica.
  • El patrón Método de fábrica oculta la construcción de un solo objeto, mientras que Abstract Factory oculta la construcción de una familia de objetos relacionados. Las fábricas abstractas generalmente se implementan utilizando (un conjunto de) métodos de fábrica.
  • El patrón Abstract Factory utiliza la composición para delegar la responsabilidad de crear un objeto a otra clase mientras que el Método Factory patrón de diseño del utiliza la herencia y se basa en una clase o subclase derivada para crear un objeto.
  • La idea detrás del patrón Método de Fábrica es que permite el caso en el que un cliente no sabe qué clases concretas deberá crear en tiempo de ejecución, pero solo quiere obtener una clase que haga el trabajo mientras Abstract Factory patrón es Se utiliza mejor cuando su sistema tiene que crear múltiples familias de productos o si desea proporcionar una biblioteca de productos sin exponer los detalles de implementación.

Implementación del patrón del método de fábrica: Método de fábrica UML

Implementación de patrones abstractos de fábrica:

Abstract Factory UML

Vibha Sanskrityayan
fuente
13
Mmm, no estoy seguro sobre el ejemplo abstracto de fábrica. Creo que la fábrica de formas y la fábrica de colores deberían implementar los mismos métodos. Pero si tengo razón, la muestra no tiene sentido.
Joaquin Iurchuk
44
Las viñetas son correctas; sin embargo, ambos diagramas están completamente equivocados y son muy engañosos. Vea el diagrama a continuación de @ Trying para obtener un modelo preciso de Abstract Factory.
jaco0646
1
Tengo que estar de acuerdo en que los 2 diagramas son muy engañosos. Los he visto en el sitio web de tutorialspoint y, para ser sincero, no estoy 100% de acuerdo con ellos. Sin embargo, las descripciones se ven bien
SoftwareDeveloper
Esto es muy engañoso.
diyoda_
Más de 50 votos a favor y los diagramas están muy equivocados. Prueba de que no puede confiar en muchas respuestas de patrones de diseño en SO.
Fuhrmanator
27

La principal diferencia entre Abstract Factory y Factory Method es que Abstract Factory se implementa mediante Composition ; pero el Método de Fábrica es implementado por Herencia .

Sí, lo has leído correctamente: la principal diferencia entre estos dos patrones es la composición anterior y la herencia debate de .

Los diagramas UML se pueden encontrar en el libro (GoF). Quiero proporcionar ejemplos de código, porque creo que combinar los ejemplos de las dos respuestas principales en este hilo dará una mejor demostración que cualquiera de las respuestas por sí sola. Además, he usado la terminología del libro en los nombres de clases y métodos.

Fábrica abstracta

  1. El punto más importante a entender aquí es que la fábrica abstracta se inyecta en el cliente. Es por eso que decimos que Abstract Factory es implementado por Composition. A menudo, un marco de inyección de dependencia realizaría esa tarea; pero no se requiere un marco para DI.
  2. El segundo punto crítico es que las fábricas de concreto aquí no son implementaciones del Método de Fábrica! El código de ejemplo para el Método de fábrica se muestra más abajo.
  3. Y finalmente, el tercer punto a tener en cuenta es la relación entre los productos: en este caso, las colas de salida y respuesta. Una fábrica de concreto produce colas de Azure, la otra MSMQ. El GoF se refiere a esta relación de producto como una "familia" y es importante tener en cuenta que la familia en este caso no significa jerarquía de clases.
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étodo de la fábrica

  1. El punto más importante a entender aquí es que ConcreteCreator es el cliente. En otras palabras, el cliente es una subclase cuyo padre define el factoryMethod(). Es por eso que decimos que el Método de Fábrica es implementado por Herencia.
  2. El segundo punto crítico es recordar que el Patrón del Método de Fábrica no es más que una especialización del Patrón del Método de la Plantilla. Los dos patrones comparten una estructura idéntica. Solo difieren en propósito. Factory Method es creacional (crea algo) mientras que Template Method es conductual (calcula algo).
  3. Y finalmente, el tercer punto a tener en cuenta es que la Creatorclase (padre) invoca la suya factoryMethod(). Si eliminamos anOperation()de la clase padre, dejando solo un método, ya no es el patrón Método de Fábrica. En otras palabras, el Método Factory no se puede implementar con menos de dos métodos en la clase padre; y uno debe invocar al otro.
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();
    }
}

Misceláneos Y diversos patrones de fábrica

Tenga en cuenta que aunque el GoF define dos patrones Factory diferentes, estos no son los únicos patrones Factory existentes. Ni siquiera son necesariamente los patrones Factory más utilizados. Un tercer ejemplo famoso es el patrón de fábrica estática de Josh Bloch de Effective Java. El libro Head First Design Patterns incluye otro patrón que ellos llaman Simple Factory.

No caigas en la trampa de asumir que cada patrón de Fábrica debe coincidir con uno del GoF.

jaco0646
fuente
3
Excelente y muy clara respuesta basada en buenos ejemplos, la mejor en este tema de la OMI.
Luke Duda el
Gran explicación +1 para el método Factory debe invocar su punto de método abstracto factory. Con este punto queda muy claro, sin entender este punto: si tenemos un método de fábrica que no se invoca por sí mismo, implica que será utilizado por alguna otra clase que lo compondrá y sus subclases se inyectarán, se convierte en fábrica abstracta , diferencia se vuelve menos claro si el punto de que método de fábrica resumen debe ser invocada por la propia fábrica como patrón método de la plantilla no se entiende
nits.kk
Una pregunta-comentario más. ¿Debería factoryMethod()ser siempre el protected método en el patrón "Método de fábrica"? (Creo que sí)
Yaroslav Fedoruk
1
@YaroslavFedoruk, el libro GoF permite publicmétodos de fábrica, y el método ni siquiera necesita ser abstract; pero el punto crítico es que el método está destinado a la herencia, por lo que no puede (por ejemplo) ser statico final. He hecho el método protectedy abstractaquí para resaltar la extensibilidad (requerida).
jaco0646
@ nits.kk, puede interesarle una respuesta relacionada .
jaco0646
26

Abstract Factory es una interfaz para crear productos relacionados, pero Factory Method es solo un método. Abstract Factory puede implementarse mediante múltiples métodos de fábrica.

Abstract Factory UML

Molesto
fuente
10
Ya has publicado la misma respuesta aquí . Si cree que esta pregunta es similar, márquela como un duplicado.
Ja͢ck
11

Considere este ejemplo para una fácil comprensión.

¿Qué proporcionan las empresas de telecomunicaciones? Banda ancha, línea telefónica y móvil, por ejemplo, y se le pide que cree una aplicación para ofrecer sus productos a sus clientes.

En general, lo que haría aquí es crear los productos, es decir, banda ancha, línea telefónica y dispositivos móviles, a través de su Método de fábrica donde sabe qué propiedades tiene para esos productos y es bastante sencillo.

Ahora, la compañía quiere ofrecer a sus clientes un paquete de sus productos, es decir, banda ancha, línea telefónica y dispositivos móviles, y aquí viene Abstract Factory para jugar.

Abstract Factory es, en otras palabras, la composición de otras fábricas que son responsables de crear sus propios productos y Abstract Factory sabe cómo colocar estos productos de manera más significativa con respecto a sus propias responsabilidades.

En este caso, BundleFactoryes la Fábrica abstracta BroadbandFactory, PhonelineFactoryy MobileFactoryson las Factory. Para simplificar más, estas Fábricas tendrán un Método de Fábrica para inicializar los productos individuales.

Vea el ejemplo de código a continuación:

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.
    }
}

Espero que esto ayude.

Abdul Munim
fuente
1
No hay staticmétodos en ninguno de los patrones de fábrica de GoF. Esto está mal.
jaco0646
5

Ejemplo de la vida real. (Fácil de recordar)

Fábrica

Imagina que estás construyendo una casa y te acercas a un carpintero por una puerta. Usted da la medida de la puerta y sus requisitos, y él construirá una puerta para usted. En este caso, el carpintero es una fábrica de puertas. Sus especificaciones son entradas para la fábrica, y la puerta es la salida o el producto de la fábrica.

Fábrica abstracta

Ahora, considere el mismo ejemplo de la puerta. Puede ir a un carpintero, o puede ir a una tienda de puertas de plástico o una tienda de PVC. Todos ellos son fábricas de puertas. Según la situación, usted decide a qué tipo de fábrica debe dirigirse. Esto es como una fábrica abstracta.

He explicado aquí tanto el patrón del método Factory como el patrón abstracto de la fábrica, comenzando por no usarlos para explicar los problemas y luego resolverlos usando los patrones anteriores https://github.com/vikramnagineni/Design-Patterns/tree/master

Vikram Babu Nagineni
fuente
3

Dejemos en claro que la mayoría de las veces en el código de producción, utilizamos un patrón de fábrica abstracto porque la clase A está programada con la interfaz B. Y A necesita crear instancias de B. Entonces, A tiene que tener un objeto de fábrica para producir instancias de B Entonces, A no depende de ninguna instancia concreta de B. Espero que ayude.

Adrian Liu
fuente
3

Comprende las diferencias en las motivaciones:

Suponga que está construyendo una herramienta donde tiene objetos y una implementación concreta de las interrelaciones de los objetos. Como prevé variaciones en los objetos, ha creado una indirección al asignar la responsabilidad de crear variantes de los objetos a otro objeto ( lo llamamos fábrica abstracta ). Esta abstracción encuentra un gran beneficio ya que prevé futuras extensiones que necesitarán variantes de esos objetos.

Otra motivación bastante intrigante en esta línea de pensamiento es un caso en el que todos o ninguno de los objetos de todo el grupo tendrán una variante correspondiente. Según algunas condiciones, se utilizará cualquiera de las variantes y en cada caso todos los objetos deben ser de la misma variante. Esto podría ser un poco contra intuitivo de entender, ya que a menudo tendemos a pensar que, siempre y cuando las variantes de un objeto sigan un contrato uniforme común ( interfaz en sentido más amplio ), el código de implementación concreto nunca debería romperse. El hecho intrigante aquí es que, no siempre esto es cierto, especialmente cuando el comportamiento esperado no puede ser modelado por un contrato de programación.

Un simple ( tomando prestada la idea de GoF ) es cualquier aplicación GUI que diga un monitor virtual que emule la apariencia de MS o Mac o Fedora OS. Aquí, por ejemplo, cuando todos los objetos de widgets como ventanas, botones, etc. tienen una variante MS, excepto una barra de desplazamiento que se deriva de la variante MAC, el propósito de la herramienta falla gravemente.

Estos casos anteriores forman la necesidad fundamental de Abstract Factory Pattern .

Por otro lado, imagine que está escribiendo un marco para que muchas personas puedan construir varias herramientas ( como la de los ejemplos anteriores ) utilizando su marco. Por la sola idea de un marco, no es necesario, aunque no pueda usar objetos concretos en su lógica. Prefieres poner algunos contratos de alto nivel entre varios objetos y cómo interactúan. Si bien usted ( como desarrollador de framework ) permanece en un nivel muy abstracto, cada constructor de la herramienta se ve obligado a seguir sus construcciones de framework. Sin embargo, ellos ( los creadores de herramientas ) tienen la libertad de decidir qué objeto construir y cómo interactuarán todos los objetos que crean. A diferencia del caso anterior ( de Abstract Factory Pattern ), usted ( como creador del framework) no es necesario trabajar con objetos concretos en este caso; y más bien puede permanecer en el nivel de contrato de los objetos. Además, a diferencia de la segunda parte de las motivaciones anteriores, usted o los constructores de herramientas nunca tienen la situación de mezclar objetos de variantes. Aquí, mientras el código marco permanece en el nivel de contrato, cada constructor de herramientas está restringido ( por la naturaleza del caso mismo ) a usar sus propios objetos. Las creaciones de objetos en este caso se delegan a cada implementador y los proveedores de marcos solo proporcionan métodos uniformes para crear y devolver objetos. Dichos métodos son inevitables para que el desarrollador de marcos continúe con su código y tiene un nombre especial llamado Método de fábrica ( Patrón de método de fábrica para el patrón subyacente ).

Pocas notas:

  • Si está familiarizado con el 'método de plantilla', verá que los métodos de fábrica a menudo se invocan a partir de métodos de plantilla en el caso de programas pertenecientes a cualquier forma de marco. Por el contrario, los métodos de plantilla de los programas de aplicación son a menudo simples implementaciones de algoritmos específicos y sin métodos de fábrica.
  • Además, para la integridad de los pensamientos, utilizando el marco ( mencionado anteriormente ), cuando un constructor de herramientas está construyendo una herramienta, dentro de cada método de fábrica, en lugar de crear un objeto concreto, él / ella puede delegar aún más la responsabilidad a un resumen -fabricante de objetos, siempre que el constructor de herramientas prevea variaciones de los objetos concretos para futuras extensiones.

Código de muestra:

//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
fuente
3
  1. Mi primera pregunta es sobre la fábrica abstracta. ¿Es su función permitirle crear familias de objetos concretos (que pueden depender de la fábrica específica que use) en lugar de solo un objeto concreto?

Si. La intención de Abstract Factory es:

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


  1. ¿La fábrica abstracta solo devuelve un objeto muy grande o muchos objetos dependiendo de los métodos que llame?

Idealmente, debería devolver un objeto por el método que invoca el cliente.

  1. Tengo entendido que el patrón del método de fábrica tiene una interfaz Creator que hará que ConcreteCreator se encargue de saber qué ConcreteProduct creará. ¿Es esto lo que significa al usar la herencia para manejar la instanciación de objetos?

Si. El método de fábrica usa la herencia.

  1. ¿El patrón Abstract Factory delega la responsabilidad de la instanciación de objetos a otro objeto a través de la composición? ¿Qué significa esto?

AbstractFactory define un FactoryMethod y ConcreteFactory es responsable de construir un ConcreteProduct. Simplemente siga el ejemplo de código en este artículo .

Puede encontrar más detalles en publicaciones SE relacionadas:

¿Cuál es la diferencia básica entre los patrones Factory y Abstract Factory?

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

Ravindra babu
fuente
3

El método de fábrica se basa en la herencia: la creación de objetos se delega en subclases, que implementan el método de fábrica para crear objetos.

Abstract Factory se basa en la composición de objetos: la creación de objetos se implementa en métodos expuestos en la interfaz de fábrica.

Diagrama de alto nivel de fábrica y patrón de fábrica abstracto,

diagrama

Para obtener más información sobre el método Factory, consulte este artículo .

Para obtener más información sobre el método abstracto de fábrica, consulte este artículo .

usuario2266614
fuente
2

Para hacerlo muy simple con una interfaz mínima y enfoque "// 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;
        }
    }

Aquí puntos importantes: 1. Los mecanismos Factory y AbstractFactory deben usar la herencia (System.Object-> byte, float ...); así que si tiene herencia en el programa, Factory (Abstract Factory no estaría allí probablemente) ya está allí por diseño 2. Creator (MyFactory) sabe sobre el tipo concreto, por lo que devuelve el objeto tipo concreto al llamante (Principal); En resumen, el tipo de retorno de fábrica sería una interfaz.

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();
    }
}

Puntos importantes: 1. Requisito: Honda crearía "Regular", "Sports", pero Hero crearía "DarkHorse", "Sports" y "Scooty". 2. ¿Por qué dos interfaces? Uno para el tipo de fabricante (IVehicleFactory) y otro para la fábrica de productos (IVehicle); otra forma de entender 2 interfaces es que la fábrica abstracta se trata de crear objetos relacionados 2. El problema es que los niños de IVehicleFactory regresan y IVehicle (en lugar de concreto en la fábrica); entonces obtengo la variable padre (IVehicle); luego creo un tipo concreto real llamando a CreateSingleVehicle y luego convirtiendo el objeto primario al objeto secundario real. ¿Qué pasaría si lo hago RegularBike heroRegularBike = (RegularBike)hero.CreateSingleVehicle("Regular");? obtendrá ApplicationException y es por eso que necesitamos una fábrica abstracta genérica que explicaría si fuera necesario.

Saurabh
fuente
1

Abstract Factory : una fábrica de fábricas; una fábrica que agrupa a las fábricas individuales pero relacionadas / dependientes sin especificar sus clases concretas. Ejemplo abstracto de fábrica

Fábrica : proporciona una forma de delegar la lógica de instanciación a las clases secundarias. Ejemplo de patrón de fábrica

Atul Jain
fuente
0

Yo preferiría Abstract Factory sobre Factory Method en cualquier momento. Del ejemplo de Tom Dalling (gran explicación por cierto) anterior, podemos ver que Abstract Factory es más componible, ya que todo lo que tenemos que hacer es pasar una Factory diferente al constructor (inyección de dependencia del constructor en uso aquí). Pero Factory Method requiere que introduzcamos una nueva clase (más cosas para administrar) y usemos subclases. Siempre prefiera la composición sobre la herencia.

he9lin
fuente
0

permíteme decirlo con precisión. la mayoría de las respuestas ya explicaron, proporcionaron diagramas y ejemplos también. así que mi respuesta sería solo un trazador de líneas. mis propias palabras: - “el patrón abstracto de fábrica agrega la capa abstracta sobre múltiples implementaciones de métodos de fábrica. significa que la fábrica abstracta contiene o compone uno o más patrones de métodos de fábrica "

Rey
fuente
Esto no es correcto. Esta es la idea errónea demasiado común de que Abstract Factory no es más que una fábrica de fábricas.
jaco0646
0

Muchas de las respuestas anteriores no proporcionan comparaciones de código entre Abstract Factory y Factory Method. El siguiente es mi intento de explicarlo a través de Java. Espero que ayude a alguien que necesita una explicación simple.

Como GoF dice acertadamente: Abstract Factory proporciona una interfaz para crear familias de objetos relacionados o dependientes sin especificar sus clases concretas.

        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
fuente
Esto no es correcto. Este código implementa la idea errónea demasiado común de que Abstract Factory no es más que una fábrica de fábricas.
jaco0646
1
@ jaco0646 Creo que en el patrón de método de fábrica, el enfoque está en obtener solo un producto concreto de FactoryImpl. Mientras que en el patrón abstracto de fábrica, FactoryImpls es responsable de proporcionar múltiples productos de hormigón similares / relacionados, para los cuales la interfaz de fábrica proporciona un contrato. Por lo tanto, ZooFactory no es en absoluto una fábrica de fábricas, como usted dice, sino solo una interfaz cuyos Impls proporcionan productos concretos que están relacionados entre sí. Siéntete libre de corregir mi comprensión si no estás de acuerdo.
Jatin Shashoo
En Factory Method, el enfoque está en la herencia a través de subclases, porque Factory Method es una especialización del patrón de Template Template. La respuesta más votada arriba muestra un ejemplo de código decente.
jaco0646
@ jaco0646 1. ¿Esto significa que en el ejemplo anterior, en lugar de usar interfaces para AnimalFactory y proporcionar sus implementaciones, debería haber usado una clase y anulado el método createAnimal () en sus subclases: CowAnimalFactory, LionAnimalFactory, etc. 2. Además, ¿cuáles son sus pensamientos sobre el ejemplo que se muestra para ZooFactory?
Jatin Shashoo
A la primera pregunta: sí. Al segundo, agregué mi propia respuesta a este hilo en lugar de seguir criticando cada respuesta individual.
jaco0646