Patrones de diseño de creación: Builder

Intención del patrón

  • Separar la construcción de un objeto complejo de su representación para que el mismo proceso de construcción pueda crear diferentes representaciones.
  • Procesar una representación compleja y crear uno de los diversos tipos de objeto.

Ejemplo de problema
Una aplicación necesita crear los elementos de un conjunto complejo. La especificación para el conjunto existe en un almacenamiento secundario y una de las representaciones debe ser creada en el almacenamiento primario.

Discusión
Separar el algoritmo de interpretación (por ejemplo: leer y analizar) de un mecanismo de almacenamiento (ej. un archivo RTF) del algoritmo de construcción y representación de uno de muchos otros formatos (Ej. ASCII, TeX,etc.). El foco / diferencia está en la creación de los conjuntos complejos.
El "director" invoca al servicio "Builder" para interpretar el formato externo. El Builder crea parte del objeto complejo cada vez que es llamado y mantiene todos los estados intermedios. Cuando el "producto" es terminado, el cliente recibe el resultado por parte del "Builder".
Estrcutura
El Lector encapsula el análisis de la entrada común. La jerarquía del Builder hace posible la creación polimórfica de muchas representaciones específicas.
Ejemplo
Recordemos que el patrón Builder separa la construcción de un objeto complejo de su representación y que el mismo proceso de construcción puede crear diferentes representaciones. Este patrón es usado por cadenas de Fast Food para hacer la comida de los niños. Dicha comida consiste típicamente en un ítem principal, una guarnición, una bebida y un juguete (Ej. Hamburguesa, papas fritas, una gaseosa y un dinosaurio de juguete). Puede haber variaciones en este conjunto que conforma una "cajita" para niños, pero el proceso que las "arma" es el mismo. Cuando un cliente solicita una hamburguesa, una hamburguesa con queso o bocaditos de pollo, el proceso es el mismo. El empleado del mostrador ordena a la cocina el ensamblado de un ítem principal, una guarnición y un juguete. Éstos elementos son puestos en una caja. La bebida es puesta en un vaso y permanece fuera de la caja. Este mismo proceso es usado en muchas cadenas de este tipo.
Check list

  1. Decidir si una entrada común y muchas representaciones (salidas) posibles, es el problema en cuestión.
  2. Encapsular el parseo de la entrada común en una clase Reader.
  3. Diseñar un protocolo estándar para crear todas las posibles representaciones de salida. Capturar los pasos de dicho protocolo en una interfaz Builder.
  4. Definir una clase Builder derivada por cada representación.
  5. El cliente debe poseer un objeto Reader (director) y otro Builder. Y registrar el último con el primero.
  6. El cliente le pide al Reader que "construya" al Buidler.
  7. El cliente le solicita al Builder que le devuelva el producto que corresponda.

Reglas de oro

  • Algunos patrones creacionales son complementarios: Builder puede utilizar otro de los otros patrones para implementar cuál producto debe construir.
  • Builder hace foco en construir objetos complejos paso a paso y los retorna como paso final.
  • Builder, a menudo, construye un Composite.
  • A menudo, el diseño nace como un Factory Method (menos complicado, más personalizable, proliferan las subclases) y evolucionan hacia un Abstract FactoryPrototype Builder (más flexible, más complejo) como el diseñador descubra cuánta flexibilidad es necesaria.

Ejemplo en código C#
using System;
using System.Collections;

public class MainApp
{
  public static void Main()
  { 
    // Create director and builders 
    Director director = new Director();

    Builder b1 = new ConcreteBuilder1();
    Builder b2 = new ConcreteBuilder2();

    // Construct two products 
    director.Construct(b1);
    Product p1 = b1.GetResult();
    p1.Show();

    director.Construct(b2);
    Product p2 = b2.GetResult();
    p2.Show();

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

// "Director" 
class Director
{
  // Builder uses a complex series of steps 
  public void Construct(Builder builder)
  {
    builder.BuildPartA();
    builder.BuildPartB();
  }
}

// "Builder" 
abstract class Builder
{
  public abstract void BuildPartA();
  public abstract void BuildPartB();
  public abstract Product GetResult();
}

// "ConcreteBuilder1" 
class ConcreteBuilder1 : Builder
{
  private Product product = new Product();

  public override void BuildPartA()
  {
    product.Add("PartA");
  }

  public override void BuildPartB()
  {
    product.Add("PartB");
  }

  public override Product GetResult()
  {
    return product;
  }
}

// "ConcreteBuilder2" 
class ConcreteBuilder2 : Builder
{
  private Product product = new Product();

  public override void BuildPartA()
  {
    product.Add("PartX");
  }

  public override void BuildPartB()
  {
    product.Add("PartY");
  }

  public override Product GetResult()
  {
    return product;
  }
}

// "Product" 
class Product
{
  ArrayList parts = new ArrayList();

  public void Add(string part)
  {
    parts.Add(part);
  }

  public void Show()
  {
    Console.WriteLine("\nProduct Parts -------");
    foreach (string part in parts)
      Console.WriteLine(part);
  }
}

0 comentarios:

Publicar un comentario

Muchas gracias por leer el post y comentarlo.

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