Constructor

RECU-0185 (Recurso Patrón)

Descripción

Como Patrón de diseño, el patrón Constructor es usado para permitir la creación de una variedad de objetos complejos desde un objeto fuente (Producto). El objeto fuente se compone de una variedad de partes que contribuyen individualmente a la creación de cada objeto complejo a través de un conjunto de llamadas a interfaces comunes de la clase ConstructorAbstracto

Nombre

También conocido como Builder

Clasificación

Patrón creacional

Motivación

Imaginemos el caso de un lector de textos. A menudo, el lector tendrá que interpretar y convertir un tipo de documentos a otro tipo de lenguaje. El problema radica en que no sabemos muy bien para cuantos tipos de lenguaje tendrá que estar preparado para interpretar. Se convierte en necesario crear una estructura que permita añadir una nueva especificación de un lenguaje sin modificar el lector. El patrón Constructor ofrece una solución para ello. Si imaginamos el lector como una clase que realiza un análisis de la información y que se lo pasa a una nueva subclase que realiza la conversión, esta subclase es la que irá añadiendo las especializaciones a nuevos formatos.

Aplicabildidad

Se debe usar este patrón si se quiere:

  • Que el algoritmo para la creación de objetos complejos sea independiente de las partes que construyen el objeto y cómo son ensambladas.
  • Que el proceso de construcción pueda tener diferentes representaciones para el objeto que está construido.

Estructura

La representación gráfica del modelo del patrón es la siguiente

169

Participantes

  • Constructor: Especifica una interfaz abstracta para construir partes del objeto producto.
  • ConstructorConcreto: Implementa la interfaz de Constructor, construyendo y ensamblando las partes del producto.
  • Director: Construye un objeto a través de la interfaz Constructor.
  • Producto: Representa el objeto complejo bajo construcción.

Colaboraciones

  • Cliente crea el objeto de Director y configura qué parte necesita del objeto Constructor.
  • Director notifica a Constructor qué parte del producto va a construir.
  • Constructor maneja la petición de Director y añade las partes del producto.
  • El cliente retira el producto del Constructor.

Consecuencias

  • Variaciones en la representación interna de un producto. Contructor proporciona una interfaz abstracta para la construccion del producto. La interfaz permite al Constructor ocultar la estructura interna del producto y el proceso de ensamblaje del mismo. Solo es necesario definir un nuevo tipo de constructor para cambiar la representación interna del producto.
  • Se mejora el bajo acoplamiento. El patron Constructor mejora la modularidad encapsulando el camino para la construcción y la representación del objeto complejo. Cliente no necesita conocer nada acerca de las clases que definen la estructura interna del producto ya que no aparecen en la interfaz del Constructor.

Implementación

Para hacer una correcta implementación del patrón debe atenderse a las siguientes recomendaciones:

  • Construcción de la interfaz y ensamblaje: Constructores crean los objetos bajo un modelo paso a paso. La interfaz debe de ser lo suficientemente general para permitir la construicción de todo tipos de objetos de los constructores concretos.
  • ¿Por qué no usar clases abstractas en el producto? El caso común, los productos producidos por constructores concretos difieren mucho en su representación, esto es mas difícil de manejar mediante el uso de clases abstractas.
  • Definir métodos vacíos por defecto en el Constructor.

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 Builder" */
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();
}
 
 
/** "ConcreteBuilder" */
class HawaiPizzaBuilder extends PizzaBuilder {
    public void buildMasa()   { pizza.setMasa("suave"); }
    public void buildSalsa()   { pizza.setSalsa("dulce"); }
    public void buildRelleno() { pizza.setRelleno("chorizo+alcachofas"); }
}
 
/** "ConcreteBuilder" */
class PicantePizzaBuilder extends PizzaBuilder {
    public void buildMasa()   { pizza.setMasa("cocida"); }
    public void buildSalsa()   { pizza.setSalsa("picante"); }
    public void buildRelleno() { pizza.setRelleno("pimienta+salchichón"); }
}
 
 
/** "Director" */
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();
    }
}
 
 
/** Un cliente pidiendo una pizza. */
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();
    }
}
 
 
 
/**
 *  Tenemos una segunda opción para el abstract builder.
 *  Es más transparente para su uso.
 *  Dentro del crear se llaman los métodos build.
 *  Es válido siempre y cuando no se necesite alterar
 *  el orden del llamado a los "constructores".
 *
 * 
 */
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();
}
 
/** "Director" */
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

  • Fue un patrón común para el lenguaje SmallTalk
  • Aplicaciones de procesamiento de texto RTF

Patrones Relacionados

  • Factoría abstracta: Ambos están relacionados con la construcción de objetos complejos. La principal diferencia es que Constructor se centra más en la construcción del objeto producto paso a paso, mientras que Factoría Abstracta se centra en la obtención de familias de objetos producto.
  • Composite: es lo que a menudo construye Constructor.

Contenidos relacionados

Recursos
Área: Desarrollo » Aplicaciones Java » Otras Especificaciones de Codificación de Aplicaciones Java
Código Título Tipo Carácter
RECU-0191 Factoría Abstracta Patrón Recomendado
RECU-0184 Composite Patrón Recomendado