martes, 21 de abril de 2015

Builder

Builder

Propósito: 

Construir de manera flexible un objeto complejo a partir de otro objeto complejo en una serie de pasos.

También conocido como: Builder.

Motivación:

Nos facilita la construcción de un objeto con una composición de más objetos. El caso habitual es la de construir una Interfaz de usuario.

Aplicabilidad:

Utilizar cuando:

El algoritmo para crear un objeto complejo deba ser independiente de las partes que componen el objeto y de cómo se ensamblan.

El proceso de construcción deba permitir distintas representaciones para el objeto que es construido. 

Estructura: 
Participantes:
  • Builder: Especifica una interfaz abstracta para crear las partes de un objeto Producto. 
  • ConcreteBuilder: 

             Construye y ensambla las partes del Producto. 
             Define la Representación a Crear. 
             Proporciona una interfaz para recuperar el Producto. 
  • Director: El encargado de crear el Objeto Complejo utilizando la interfaz Builder. 
  • Producto: Representa el Objeto Complejo en Construcción.

Colaboraciones:
  • El cliente crea el objeto director y lo configura con el objeto constructor deseado. 
  • El director avisa al constructor cuando una parte del producto tiene que ser construida. 
  • El constructor gestiona las peticiones del director y añade partes al producto.
  • El cliente obtiene el producto del constructor
Consecuencias:
  • Permite variar la representación interna de un Producto: como el producto se construye a través de una interfaz abstracta, para cambiar la representación interna del producto es definir un nuevo tipo de constructor.
  • Permite separar el código de la construcción y la representación.
  • Da control refinado sobre el proceso de construcción. El patrón Builder construye el producto paso a paso bajo el control del Director.
Implementación: 


El patrón de diseño del Generador utiliza el patrón de fábrica Builder para decidir qué clase concreta para iniciar el fin de construir el tipo deseado de objeto.

Código de ejemplo:

class Pizza {
private String masa = "";
private String salsa = "";
private String relleno = "";

public void setMasa(String masa) { this.masa = masa; }
public void setSalsa(String salsa) { this.salsa = salsa; }
public void setRelleno(String relleno) { this.relleno = relleno; }
}

abstract class PizzaBuilder {
protected Pizza pizza;

public Pizza getPizza() { return pizza; }
public void crearNuevaPizza() { pizza = new Pizza(); }

public abstract void buildMasa();
public abstract void buildSalsa();
public abstract void buildRelleno();
}

class HawaiPizzaBuilder extends PizzaBuilder {
public void buildMasa() { pizza.setMasa("suave"); }
public void buildSalsa() { pizza.setSalsa("dulce"); }
public void buildRelleno() { pizza.setRelleno("chorizo+alcachofas"); }
}

class PicantePizzaBuilder extends PizzaBuilder {
public void buildMasa() { pizza.setMasa("cocida"); }
public void buildSalsa() { pizza.setSalsa("picante"); }
public void buildRelleno() { pizza.setRelleno("pimienta+salchichón"); }
}

class Cocina {
private PizzaBuilder pizzaBuilder;

public void setPizzaBuilder(PizzaBuilder pb) { pizzaBuilder = pb; }
public Pizza getPizza() { return pizzaBuilder.getPizza(); }

public void construirPizza() {
pizzaBuilder.crearNuevaPizza();
pizzaBuilder.buildMasa();
pizzaBuilder.buildSalsa();
pizzaBuilder.buildRelleno();
}
}
class BuilderExample {
public static void main(String[] args) {
Cocina cocina = new Cocina();
PizzaBuilder hawai_pizzabuilder = new HawaiPizzaBuilder();
PizzaBuilder picante_pizzabuilder = new PicantePizzaBuilder();

cocina.setPizzaBuilder( hawai_pizzabuilder );
cocina.construirPizza();

Pizza pizza = cocina.getPizza();
}
}
abstract class OtroPizzaBuilder {
protected Pizza pizza;

public Pizza getPizza() { return pizza; }
public void crearNuevaPizza() {
pizza = new Pizza();
buildMasa();
buildSalsa();
buildRelleno();
}

public abstract void buildMasa();
public abstract void buildSalsa();
public abstract void buildRelleno();
}

class OtraCocina {
private OtroPizzaBuilder pizzaBuilder;

public void setPizzaBuilder(OtroPizzaBuilder pb) { pizzaBuilder = pb; }
public Pizza getPizza() { return pizzaBuilder.getPizza(); }

public void construirPizza() {
pizzaBuilder.crearNuevaPizza();
//notar que no se necesita llamar a cada build.
}
}

Usos conocidos:

Este patrón es útil en alguno de los siguientes supuestos:

  • Cuando el algoritmo para crear un objeto complejo puede independizarse de las partes que componen el objeto y de cómo son ensambladas.
  • Cuando el proceso de construcción debe permitir distintas representaciones para el objeto que se construye.
  • Cuando el objeto a construir es complejo y sus distintas configuraciones son limitadas. En caso de que necesitemos un objeto complejo pero cada una de sus partes deba ser configurado de forma individual (en el ejemplo que nos ocupa, se trataría de definir cada elemento “al gusto” del consumidor en lugar de objetos predefinidos), este patrón no será una buena idea, ya que será necesario realizar el proceso de asignación de cada elemento paso a paso.

Como ejemplos reales, GoF ilustra su aplicación con un parser RTF, en el que separa los algoritmos de procesamiento dependiendo del texto a transformar (ASCII, TEX…). Otro ejemplo puede ser la generación de distintos tipos de Sitemaps (Google, HTML…).

Patrones relacionados:
  • El patrón Abstract Factory es similar al patrón Builder debido a que también puede construir objetos complejos.
  • La principal diferencia es que el patrón Builder se centra en construir un objeto paso por paso, patrón Abstract Factory pone énfasis en familias de objetos producto (simples o complejos).
  • El patrón Builder retorna el producto como un paso final, pero el patrón Abstract Factory lo devuelve inmediatamente.
  • Un Composite es lo que el constructor a menudo construye.

No hay comentarios:

Publicar un comentario