Patrones de diseño de creación: Abstract Factory

Intención del patrón
  • Proveer una interfaz para la creación de familias de objetos, relacionados o dependientes, sin especificar su clase concreta.
  • Una jerarquía que encapsula: muchas posibles plataformas y la construcción de una suite de productos.
  • Que el operador new sea considerado como perjudicial.
Ejemplo de problema
Si una aplicación está diseñada para ser portátil, ésta necesita encapsular sus dependencias de la plataforma en la que se ejecute. Dichas plataformas podrían incluir: sistema operativo, interfaces de usuario, bases de datos, etc. Muy a menudo, éste encapsulamiento no ha sido diseñado de antemano y un montón de declaraciones del tipo #ifdef con opciones para todas las plataformas soportadas comienzan a reproducirse como conejos a través del código.
Discusión
La factoría de objetos tiene la responsabilidad de proveer servicios de creación para toda la familia de plataformas. Los clientes nunca crean directamente los objetos de una plataforma; ellos le solicitan a la factoría que les proporcione la instancia que corresponda.
Este mecanismo hace que el intercambio de familia de productos sea fácil, porque la la clase específica de la factoría de objetos aparece sólo una vez en la aplicación (cuando se crea la instancia). La aplicación puede reemplazar indiscriminadamente toda la familia de productos simplemente instanciando una diferente clase concreta de la factoría.
Debido a que el servicio provisto por la factoría de objetos es tan difundido, que por lo general es implementado como un Singleton.
Estructura
La factoría define un Factory Method por producto. Cada Factory Method encapsula el operador new y la clase, plataforma específica o producto concreto. Cada plataforma es modelada con una clase Factory derivada.
Ejemplo
Recordemos que el propósito de una Abstract Factory es proveer una interfaz capaz de crear una familia de objetos relacionados sin especificar clases concretas. Este patrón se encuentra en el equipo de estampado de láminas de metal usado en la fabricación de automóviles japoneses. El equipo de estampado es una Abstract Factory que se encarga de crear las partes de un auto. La misma maquinaria es utilizada para hacer las puertas derecha e izquierda, los guardabarros delanteros derecho e izquierdo, capós, etc. para diferentes modelos de autos. Mediante el uso de rodillos para cambiar las matrices de estampado, las clases concretas producidas por la máquina pueden ser cambiadas en tres minutos.
Check list
  1. Decidir si la "independencia de plataformas" y servicios de creación son la fuente actual de problemas.
  2. Trazar una matriz de plataformas y productos.
  3. Definir una interfaz que consista en un Factory Method por producto.
  4. Definir una clase Factory derivada por cada plataforma que encapsule toda referencia al operador new.
  5. El cliente debe retirar toda referencia al operador new y usar los Factory Method para crear los objetos.
Reglas de oro
  • A veces los patrones creacionales compiten entre ellos: existen casos en los que tanto el patrón Abstract Factory como el Prototype pueden ser usados de forma productiva. En otras ocasiones son complementarios: Abstract Factory puede almacenar un conjunto de Prototypes de los cuales clonar y retornar los objetos, el patrón Builder puede usar uno de los otros patrones para implementar cual componente debe ser instanciado. Abstract Factory, Prototype y Builder, pueden usar Simgleton en sus implementaciones.
  • Las clases Abstract Factory son a menudo implementadas con Factory Methods. Pero éstos también pueden ser implementados usando Prototype.
  • Abstract Factory puede ser usado como una alternativa a Facade para ocultar las clases específicas de las plataformas.
  • Builder hace incapié en la construcción de objetos complejos paso a paso, mientras que Abstract Factory hace énfasis en una familia de objetos (sean simples o complejos).
  • A menudo, el diseño nace como un Factory Method (menos complicado, más personalizable, proliferan las subclases) y evolucionan hacia un Abstract Factory, Prototype o Builder (más flexible, más complejo) como el diseñador descubra cuánta flexibilidad es necesaria.
Ejemplo en código C#
using System;

class MainApp
{
  public static void Main()
  {
    // Abstract factory #1 
    AbstractFactory factory1 = new ConcreteFactory1();
    Client c1 = new Client(factory1);
    c1.Run();

    // Abstract factory #2 
    AbstractFactory factory2 = new ConcreteFactory2();
    Client c2 = new Client(factory2);
    c2.Run();

    // Wait for user input 
    Console.Read();
  }
}

// "AbstractFactory" 
abstract class AbstractFactory
{
  public abstract AbstractProductA CreateProductA();
  public abstract AbstractProductB CreateProductB();
}

// "ConcreteFactory1" 
class ConcreteFactory1 : AbstractFactory
{
  public override AbstractProductA CreateProductA()
  {
    return new ProductA1();
  }
  public override AbstractProductB CreateProductB()
  {
    return new ProductB1();
  }
}

// "ConcreteFactory2" 
class ConcreteFactory2 : AbstractFactory
{
  public override AbstractProductA CreateProductA()
  {
    return new ProductA2();
  }
  public override AbstractProductB CreateProductB()
  {
    return new ProductB2();
  }
}

// "AbstractProductA" 
abstract class AbstractProductA
{
}

// "AbstractProductB" 
abstract class AbstractProductB
{
  public abstract void Interact(AbstractProductA a);
}

// "ProductA1" 
class ProductA1 : AbstractProductA
{
}

// "ProductB1" 
class ProductB1 : AbstractProductB
{
  public override void Interact(AbstractProductA a)
  {
    Console.WriteLine(this.GetType().Name + " interacts with " + a.GetType().Name);
  }
}

// "ProductA2" 
class ProductA2 : AbstractProductA
{
}

// "ProductB2" 
class ProductB2 : AbstractProductB
{
  public override void Interact(AbstractProductA a)
  {
    Console.WriteLine(this.GetType().Name + " interacts with " + a.GetType().Name);
  }
}

// "Client" - the interaction environment of the products 
class Client
{
  private AbstractProductA AbstractProductA;
  private AbstractProductB AbstractProductB;

  // Constructor 
  public Client(AbstractFactory factory)
  {
    AbstractProductB = factory.CreateProductB();
    AbstractProductA = factory.CreateProductA();
  }

  public void Run()
  {
    AbstractProductB.Interact(AbstractProductA);
  }
}

2 comentarios:

Anónimo dijo...

bien Abstract Factory

Juan Barrionuevo dijo...

Muchas gracias por tu comentario.
Espero que encuentres otras cosas que te agraden en el blog.

Publicar un comentario

Muchas gracias por leer el post y comentarlo.

 
Copyright 2009 Programación SOLIDa
BloggerTheme by BloggerThemes | Design by 9thsphere