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

183

Estaba leyendo patrones de diseño de un sitio web

Allí leí sobre Fábrica, Método de fábrica y Fábrica abstracta, pero son tan confusos que no tengo clara la definición. De acuerdo con las definiciones

Fábrica: crea objetos sin exponer la lógica de creación de instancias al cliente y hace referencia al objeto recién creado a través de una interfaz común. Es una versión simplificada del Método Factory

Método de fábrica: define una interfaz para crear objetos, pero permite que las subclases decidan qué clase instanciar y se refiere al objeto recién creado a través de una interfaz común.

Abstract Factory: ofrece la interfaz para crear una familia de objetos relacionados, sin especificar explícitamente sus clases.

También miré los otros hilos de stackoverflow con respecto a Abstract Factory vs Factory Method, pero los diagramas UML dibujados allí hacen que mi comprensión sea aún peor.

¿Alguien puede decirme?

  1. ¿En qué se diferencian estos tres patrones entre sí?
  2. ¿Cuándo usar cuál?
  3. Y también, si es posible, ¿hay ejemplos de Java relacionados con estos patrones?
Just_another_developer
fuente
3
Mientras buscaba respuestas a aproximadamente la misma pregunta que el OP, encontré este artículo: De ninguna fábrica al método de fábrica . Proporciona información al seguir la evolución de un proyecto de muestra (el método de fábrica mencionado en el título es uno de los pasos evolutivos).
Nick Alexeev

Respuestas:

251

Los tres tipos de Fábrica hacen lo mismo: son un "constructor inteligente".

Digamos que desea poder crear dos tipos de fruta: manzana y naranja.

Fábrica

Factory es "fijo", ya que solo tiene una implementación sin subclases. En este caso, tendrá una clase como esta:

class FruitFactory {

  public Apple makeApple() {
    // Code for creating an Apple here.
  }

  public Orange makeOrange() {
    // Code for creating an orange here.
  }

}

Caso de uso: la construcción de una manzana o una naranja es demasiado compleja para manejarla en el constructor.

Método de la fábrica

El método de fábrica generalmente se usa cuando tienes un procesamiento genérico en una clase, pero quieres variar qué tipo de fruta realmente usas. Entonces:

abstract class FruitPicker {

  protected abstract Fruit makeFruit();

  public void pickFruit() {
    private final Fruit f = makeFruit(); // The fruit we will work on..
    <bla bla bla>
  }
}

... entonces puede reutilizar la funcionalidad común FruitPicker.pickFruit()implementando un método de fábrica en subclases:

class OrangePicker extends FruitPicker {

  @Override
  protected Fruit makeFruit() {
    return new Orange();
  }
}

Fábrica abstracta

La fábrica abstracta normalmente se usa para cosas como la inyección / estrategia de dependencia, cuando se quiere poder crear una familia completa de objetos que necesitan ser "del mismo tipo" y tener algunas clases base comunes. Aquí hay un ejemplo vagamente relacionado con la fruta. El caso de uso aquí es que queremos asegurarnos de que no usamos accidentalmente un OrangePicker en una Apple. Siempre que obtengamos nuestra Fruta y Recogedor de la misma fábrica, coincidirán.

interface PlantFactory {

  Plant makePlant();

  Picker makePicker(); 

}

public class AppleFactory implements PlantFactory {
  Plant makePlant() {
    return new Apple();
  }

  Picker makePicker() {
    return new ApplePicker();
  }
}

public class OrangeFactory implements PlantFactory {
  Plant makePlant() {
    return new Orange();
  }

  Picker makePicker() {
    return new OrangePicker();
  }
}
Anders Johansen
fuente
8
+1 Esta es la respuesta que más se parece a mi comprensión de estos patrones. ¿También sería útil agregar ejemplos de código de llamada (Cliente)? La pregunta que me molesta mucho es: ¿podemos decir que Abstract Factory Pattern es solo Factory ampliado con Factory Method Pattern (si esto es cierto, tengo claro este tema)?
croraf
9
Este es el ejemplo que he pasado años buscando.
Taztingo
¡Esa es una explicación fantástica! ¡Gracias!
André Andrade
@ AndréAndrade ¿Cómo invocar el Método de Fábrica ? Un pequeño código samle pls :) Eso aclarará mi duda sobre su uso
Arnab Dutta
25
  1. ¿En qué se diferencian estos tres patrones entre sí?

Fábrica: Crea objetos sin exponer la lógica de instanciación al cliente.

Método de fábrica: defina una interfaz para crear un objeto, pero deje que las subclases decidan qué clase instanciar. El método Factory permite que una clase difiera la creación de instancias en subclases

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

El patrón AbstractFactory usa la composición para delegar la responsabilidad de crear objetos a otra clase, mientras que el patrón de diseño del método Factory usa la herencia y se basa en la clase derivada o subclase para crear el objeto

  1. ¿Cuándo usar cuál?

Fábrica: el cliente solo necesita una clase y no le importa qué implementación concreta esté obteniendo.

Método de fábrica: el cliente no sabe qué clases concretas se requerirán para crear en tiempo de ejecución, pero solo quiere obtener una clase que haga el trabajo.

AbstactFactory: cuando su sistema tiene que crear varias familias de productos o si desea proporcionar una biblioteca de productos sin exponer los detalles de implementación.

Las clases Abstract Factory a menudo se implementan con el Método Factory. Los métodos de fábrica generalmente se llaman dentro de los métodos de plantilla.

  1. Y también, si es posible, ¿hay ejemplos de Java relacionados con estos patrones?

Factory y FactoryMethod

Intención:

Defina una interfaz para crear un objeto, pero permita que las subclases decidan qué clase instanciar. Factory Method permite que una clase difiera la creación de instancias en subclases.

Diagrama UML :

ingrese la descripción de la imagen aquí

Producto: define una interfaz de los objetos que crea el método Factory.

ConcreteProduct: implementa la interfaz del producto

Creador: declara el método Factory

ConcreateCreator: implementa el método Factory para devolver una instancia de un ConcreteProduct

Planteamiento del problema: cree una Fábrica de juegos utilizando los Métodos de fábrica, que definen la interfaz del juego.

Fragmento de código:

Patrón de fábrica ¿Cuándo usar los métodos de fábrica?

Comparación con otros patrones de creación:

  1. El diseño comienza con el Método Factory (menos complicado, más personalizable, proliferan las subclases) y evoluciona hacia Abstract Factory, Prototype o Builder (más flexible, más complejo) a medida que el diseñador descubre dónde se necesita más flexibilidad

  2. Las clases de Fábrica abstracta a menudo se implementan con Métodos de fábrica , pero también se pueden implementar utilizando Prototype

Referencias para lecturas adicionales: patrones de diseño de creación de código fuente

Ravindra babu
fuente
Para el Método de fábrica, ¿no debería definirse una superclase?
Tony Lin
21

Factory : clase Factory separada para crear objetos complejos.

Ej: clase FruitFactory para crear objeto de Fruit

class FruitFactory{

public static Fruit getFruit(){...}

}

Método de fábrica : en lugar de toda una clase separada para la fábrica, simplemente agregue un método en esa clase como fábrica.

Ex:

Calendar.getInstance() (Java's Calendar)

Método de Fábrica Abstracta - Fábrica de Fábrica

Ej: Digamos que queremos construir una fábrica para partes de computadoras. Así que hay varios tipos de computadoras como Laptop, Desktop, Server.

Entonces, para cada tipo de compilador necesitamos fábrica. Entonces creamos una fábrica de fábricas de alto nivel como la siguiente

ComputerTypeAbstractFactory.getComputerPartFactory(String computerType) ---> This will return PartFactory which can be one of these ServerPartFactory, LaptopPartFactory, DesktopPartFactory.

Ahora estos 3 en sí mismos son de nuevo fábricas. (Se ocupará de PartFactory en sí, pero bajo el capó, habrá una implementación separada basada en lo que proporcionó en la fábrica abstracta)

  Interface-> PartFactory. getComputerPart(String s), 
Implementations -> ServerPartFactory, LaptopPartFactory, DesktopPartFactory.

Usage:
new ComputerTypeAbstractFactory().getFactory(“Laptop”).getComputerPart(“RAM”)

EDITAR: editado para proporcionar interfaces exactas para Abstract Factory según las objeciones en los comentarios.

Ravi K
fuente
1
La idea detrás de ComputerFactoryesto sería que tiene una interfaz de creación común ( getScreen(); getKeyboard(); getDiskdrive(); ...), no una interfaz por tipo de computadora como sugiere. Puede oler un problema de diseño si usa la misma palabra dos veces en la misma declaración: Laptop Factory.get Laptop Part ().
xtofl
No no no, no sigas exactamente el código en sí. Era solo una anología para la comprensión. Si desea un ejemplo exacto con interfaces, aquí está. Objetos: Interfaz -> ComputerPart, Implementación -> RAM, HDD, Fábrica de procesadores: Interfaz-> PartFactory. getComputerPart (String s), Implementaciones -> ServerPartFactory, LaptopPartFactory, DesktopPartFactory. Fábrica abstracta: ComputerType.getPartFactory ("String s") Uso: nuevo ComputerType (). GetFactory ("Laptop"). GetComputerPart ("RAM")
Ravi K
2
He actualizado la respuesta para atender su inquietud. En realidad, la fábrica abstracta no es más que un factor de fábrica únicamente. Di un ejemplo anterior solo como referencia (suponiendo que los lectores se encargarán de las interfaces durante la implementación real). Aún así, gracias por notificar. Siempre es bueno mejorar. :)
Ravi K
No abstract Factory, no es una fábrica de la fábrica ... Es un abstract classo un interfacepoder crear el objeto que será implementado / extendida con distintas fábricas de hormigón. Consulte la respuesta aceptada para obtener detalles del código. Y elimine o edite su respuesta en consecuencia.
Julien__
Me gusta la explicación del método de fábrica, que es lo suficientemente conciso como para revelar por qué se llama así. En este patrón, la fábrica es el método, NO la clase que generalmente no es una utilidad auxiliar que agrupa los métodos de creación de instancias, sino que es significativa por sí misma. Desafortunadamente, otras respuestas más elaboradas pasaron por alto este punto.
wlnirvana
11

Cada patrón de diseño prospera para ayudar a garantizar que no se toque el código de trabajo escrito. Todos sabemos que una vez que tocamos el código de trabajo, hay defectos en los flujos de trabajo existentes, y es necesario realizar muchas más pruebas para garantizar que no hayamos roto nada.

Un patrón de fábrica crea objetos basados ​​en criterios de entrada, asegurando así que no necesite escribir código como si fuera así, luego cree este tipo de objeto o este tipo de objeto. Un buen ejemplo de esto es un sitio web de viajes. Un sitio web de viajes solo puede proporcionar viajes (vuelo, tren, autobús) o / y proporcionar hoteles o / y proporcionar paquetes de atracciones turísticas. Ahora, cuando un usuario selecciona a continuación, el sitio web necesita decidir qué objetos necesita crear. Si solo crea el objeto de viaje u hotel también.

Ahora, si imagina agregar otro sitio web a su cartera, y cree que se usará el mismo núcleo, por ejemplo, un sitio web de viajes compartidos, que ahora busca taxis y realiza pagos en línea, puede usar una fábrica abstracta en su núcleo. De esta manera, puede instalar una fábrica más de taxis y vehículos compartidos.

Ambas fábricas no tienen nada que ver entre sí, por lo que es un buen diseño para mantenerlas en fábricas diferentes.

Espero que esto esté claro ahora. Estudie el sitio web nuevamente teniendo en cuenta este ejemplo, con suerte le ayudará. Y realmente espero haber representado los patrones correctamente :).

Siddharth
fuente
3

Para esta respuesta, me refiero al libro "Gang of Four".

No hay definiciones de "Fábrica" ​​ni de "Fábrica simple" ni de "Fábrica virtual" en el libro. Por lo general, cuando las personas hablan sobre el patrón "Factory", pueden estar hablando sobre algo que crea un objeto particular de una clase (pero no el patrón "constructor"); que puede o no puede hacer referencia a la "Factory Method" o "patrones Resumen de fábrica". Cualquiera puede implementar "Fábrica" ​​como no lo hará porque no es un término formal (tenga en cuenta que algunas personas, empresas y comunidades pueden tener su propio vocabulario).

El libro solo contiene definiciones para "Fábrica abstracta" y "Método de fábrica".

Aquí hay definiciones del libro y una breve explicación de por qué ambos pueden ser tan confusos. Omito ejemplos de código porque puedes encontrarlos en otras respuestas:

Método de fábrica (GOF) : defina una interfaz para crear un objeto, pero permita que las subclases decidan qué clase instanciar. Factory Method permite que una clase difiera la creación de instancias en subclases.

Abstract Factory (GOF) : proporciona una interfaz para crear familias de objetos relacionados o dependientes sin especificar sus clases concretas.

Fuente de confusión : a menudo, se puede llamar a una clase que se usa en el patrón "Método de fábrica" ​​como "Fábrica". Esta clase es abstracta por definición. Por eso es fácil llamar a esta clase "Fábrica abstracta". Pero es solo el nombre de la clase; no debe confundirlo con el patrón "Abstract Factory" (nombre de clase! = nombre del patrón). El patrón "Fábrica abstracta" es diferente: no utiliza una clase abstracta; define una interfaz (no necesariamente una interfaz de lenguaje de programación) para crear partes de un objeto más grande u objetos que están relacionados entre sí o deben crearse de una manera particular.

Pavel Sapehin
fuente
2
AbstractProductA, A1 and A2 both implementing the AbstractProductA
AbstractProductB, B1 and B2 both implementing the AbstractProductB

interface Factory {
    AbstractProductA getProductA(); //Factory Method - generate A1/A2
}

Usando el Método de Fábrica, el usuario puede crear A1 o A2 de AbstractProductA.

interface AbstractFactory {
    AbstractProductA getProductA(); //Factory Method
    AbstractProductB getProductB(); //Factory Method
}

Pero Abstract Factory tiene más de 1 método de fábrica (por ejemplo: 2 métodos de fábrica), utilizando esos métodos de fábrica creará el conjunto de objetos / objetos relacionados. Usando Abstract Factory, el usuario puede crear objetos A1, B1 de AbstractProductA, AbstractProductB

rameshvanka
fuente
0

Nadie ha citado el libro original Design Patterns: Elements of Reusable Object-Oriented Software , que da la respuesta en los primeros dos párrafos de la sección "Discusión de los patrones creacionales" (énfasis mío):

Hay dos formas comunes de parametrizar un sistema por las clases de objetos que crea. Una forma es subclasificar la clase que crea los objetos; esto corresponde a usar el patrón Método de fábrica (107). El principal inconveniente de este enfoque es que puede requerir una nueva subclase solo para cambiar la clase del producto. Tales cambios pueden caer en cascada. Por ejemplo, cuando el creador del producto es creado por un método de fábrica, también debe anularlo.

La otra forma de parametrizar un sistema se basa más en la composición de objetos : defina un objeto responsable de conocer la clase de los objetos del producto y conviértalo en un parámetro del sistema. Este es un aspecto clave de los patrones Abstract Factory (87), Builder (97) y Prototype (117). Los tres implican crear un nuevo "objeto de fábrica" ​​cuya responsabilidad es crear objetos de producto. Abstract Factory tiene el objeto de fábrica que produce objetos de varias clases. El constructor tiene el objeto de fábrica que construye un producto complejo de manera incremental utilizando un protocolo correspondientemente complejo. Prototype tiene el objeto de fábrica que construye un producto copiando un objeto prototype. En este caso, el objeto de fábrica y el prototipo son el mismo objeto, porque el prototipo es responsable de devolver el producto.

Maggyero
fuente