Patrón de fábrica abstracto

Introducción

El patrón de diseño Abstract Factory es uno de los patrones de creación. El patrón de fábrica abstracto es casi similar al patrón de fábrica y se considera como otra capa de abstracción sobre el patrón de fábrica. Los patrones de Abstract Factory funcionan en torno a una superfábrica que crea otras fábricas.
La implementación de patrones de fábrica abstractos nos proporciona un marco que nos permite crear objetos que siguen un patrón general. Entonces, en tiempo de ejecución, la fábrica abstracta se combina con cualquier fábrica concreta deseada que puede crear objetos del tipo deseado.
Veamos la representación GOF de Abstract Factory Pattern: 
 

Ejemplo de diagrama de clase UML para el patrón de diseño de fábrica abstracta. 
 

  • AbstractFactory : declara una interfaz para operaciones que crean objetos de productos abstractos. 
  • ConcreteFactory : implementa las operaciones declaradas en AbstractFactory para crear objetos de productos concretos.
  • Producto : Define un objeto de producto para ser creado por la fábrica concreta correspondiente e implementa la interfaz AbstractProduct.
  • Cliente : utiliza solo las interfaces declaradas por las clases AbstractFactory y AbstractProduct.

Abstract Factory proporciona interfaces para crear familias de objetos relacionados o dependientes sin especificar sus clases concretas.
El software del cliente crea una implementación concreta de la fábrica abstracta y luego usa las interfaces genéricas para crear los objetos concretos que forman parte de la familia de objetos. 
El cliente no sabe ni le importa qué objetos concretos obtiene de cada una de estas fábricas concretas ya que utiliza únicamente las interfaces genéricas de sus productos.
Entonces, con esta idea del patrón Abstract Factory, ahora intentaremos crear un diseño que facilite la creación de objetos relacionados. 
 

Implementación

Tomemos un ejemplo, supongamos que queremos construir una fábrica de automóviles global. Si era un patrón de diseño de fábrica , entonces era adecuado para una sola ubicación. Pero para este patrón, necesitamos varias ubicaciones y algunos cambios de diseño críticos.
Necesitamos fábricas de automóviles en cada ubicación, como IndiaCarFactory, USACarFactory y DefaultCarFactory. Ahora, nuestra aplicación debe ser lo suficientemente inteligente como para identificar la ubicación donde se está utilizando, por lo que deberíamos poder usar la fábrica de automóviles adecuada sin siquiera saber qué implementación de fábrica de automóviles se usará internamente. Esto también nos evita que alguien llame a la fábrica equivocada para una ubicación en particular.
Aquí necesitamos otra capa de abstracción que identifique la ubicación y use internamente la implementación correcta de fábrica de automóviles sin siquiera dar una sola pista al usuario. Este es exactamente el problema, que se utiliza para resolver un patrón de fábrica abstracto.
 

Java

// Java Program to demonstrate the
// working of Abstract Factory Pattern
 
enum CarType
{
    MICRO, MINI, LUXURY
}
 
abstract class Car
{
    Car(CarType model, Location location)
    {
        this.model = model;
        this.location = location;
    }
  
    abstract void construct();
  
    CarType model = null;
    Location location = null;
  
    CarType getModel()
    {
        return model;
    }
  
    void setModel(CarType model)
    {
        this.model = model;
    }
  
    Location getLocation()
    {
        return location;
    }
  
    void setLocation(Location location)
    {
        this.location = location;
    }
  
    @Override
    public String toString()
    {
        return "CarModel - "+model + " located in "+location;
    }
}
 
class LuxuryCar extends Car
{
    LuxuryCar(Location location)
    {
        super(CarType.LUXURY, location);
        construct();
    }
    @Override
    protected void construct()
    {
        System.out.println("Connecting to luxury car");
    }
}
 
class MicroCar extends Car
{
    MicroCar(Location location)
    {
        super(CarType.MICRO, location);
        construct();
    }
    @Override
    protected void construct()
    {
        System.out.println("Connecting to Micro Car ");
    }
}
 
class MiniCar extends Car
{
    MiniCar(Location location)
    {
        super(CarType.MINI,location );
        construct();
    }
     
    @Override
    void construct()
    {
        System.out.println("Connecting to Mini car");
    }
}
 
enum Location
{
  DEFAULT, USA, INDIA
}
 
class INDIACarFactory
{
    static Car buildCar(CarType model)
    {
        Car car = null;
        switch (model)
        {
            case MICRO:
                car = new MicroCar(Location.INDIA);
                break;
             
            case MINI:
                car = new MiniCar(Location.INDIA);
                break;
                 
            case LUXURY:
                car = new LuxuryCar(Location.INDIA);
                break;
                 
                default:
                break;
             
        }
        return car;
    }
}
 
class DefaultCarFactory
{
    public static Car buildCar(CarType model)
    {
        Car car = null;
        switch (model)
        {
            case MICRO:
                car = new MicroCar(Location.DEFAULT);
                break;
             
            case MINI:
                car = new MiniCar(Location.DEFAULT);
                break;
                 
            case LUXURY:
                car = new LuxuryCar(Location.DEFAULT);
                break;
                 
                default:
                break;
             
        }
        return car;
    }
}
 
 
class USACarFactory
{
    public static Car buildCar(CarType model)
    {
        Car car = null;
        switch (model)
        {
            case MICRO:
                car = new MicroCar(Location.USA);
                break;
             
            case MINI:
                car = new MiniCar(Location.USA);
                break;
                 
            case LUXURY:
                car = new LuxuryCar(Location.USA);
                break;
                 
                default:
                break;
             
        }
        return car;
    }
}
 
 
 
class CarFactory
{
    private CarFactory()
    {
         
    }
    public static Car buildCar(CarType type)
    {
        Car car = null;
        // We can add any GPS Function here which
        // read location property somewhere from configuration
        // and use location specific car factory
        // Currently I'm just using INDIA as Location
        Location location = Location.INDIA;
         
        switch(location)
        {
            case USA:
                car = USACarFactory.buildCar(type);
                break;
                 
            case INDIA:
                car = INDIACarFactory.buildCar(type);
                break;
                     
            default:
                car = DefaultCarFactory.buildCar(type);
 
        }
         
        return car;
 
    }
}
 
class AbstractDesign
{
    public static void main(String[] args)
    {
        System.out.println(CarFactory.buildCar(CarType.MICRO));
        System.out.println(CarFactory.buildCar(CarType.MINI));
        System.out.println(CarFactory.buildCar(CarType.LUXURY));
    }
}

Producción : 
 

Connecting to Micro Car 
CarModel - MICRO located in INDIA
Connecting to Mini car
CarModel - MINI located in INDIA
Connecting to luxury car
CarModel - LUXURY located in INDIA

Diferencia

  • 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. 
  • El método de fábrica es solo un método, se puede anular en una subclase, mientras que la fábrica abstracta es un objeto que tiene múltiples métodos de fábrica.
  • El patrón Factory Method usa la herencia y se basa en una subclase para manejar la creación de instancias del objeto deseado.

Ventajas: este patrón es particularmente útil cuando el cliente no sabe exactamente qué tipo crear. 

  • Aislamiento de clases concretas: El patrón Abstract Factory te ayuda a controlar las clases de objetos que crea una aplicación. Debido a que una fábrica encapsula la responsabilidad y el proceso de crear objetos de productos, aísla a los clientes de las clases de implementación. Los clientes manipulan instancias a través de sus interfaces abstractas. Los nombres de las clases de productos se aíslan en la implementación de la fábrica de hormigón; no aparecen en el código del cliente.
  • Intercambiar familias de productos fácilmente: La clase de una fábrica concreta aparece solo una vez en una aplicación, ahí es donde se instancia. Esto facilita cambiar la fábrica concreta que usa una aplicación. Puede utilizar varias configuraciones de productos simplemente cambiando la fábrica de hormigón. Debido a que una fábrica abstracta crea una familia completa de productos, toda la familia de productos cambia a la vez.
  • Promoción de la coherencia entre los productos: cuando los objetos de productos de una familia están diseñados para trabajar juntos, es importante que una aplicación utilice objetos de una sola familia a la vez. AbstractFactory hace que esto sea fácil de aplicar.n.

Desventajas

  • Difícil soportar nuevos tipos de productos: No es fácil extender fábricas abstractas para producir nuevos tipos de productos. Eso es porque la interfaz AbstractFactory fija el conjunto de productos que se pueden crear. La compatibilidad con nuevos tipos de productos requiere ampliar la interfaz de fábrica, lo que implica cambiar la clase AbstractFactory y todas sus subclases.

De alguna manera, el ejemplo anterior también se basa en cómo funcionan los taxis como uber y ola a gran escala.
Lectura adicional: método de fábrica abstracto en Python
Este artículo es una contribución de Saket Kumar . Si te gusta GeeksforGeeks y te gustaría contribuir, también puedes escribir un artículo usando write.geeksforgeeks.org o enviar tu artículo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.
Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.
 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *