Patrones de Diseño (III): Patrones de Creación - Builder

Como hemos dicho, mediante este patrón pretendemos crear objetos complejos a partir de un objeto fuente, también denominado producto, centralizando el proceso de creación en un único punto. Esto nos permite mediante un procedimiento único, crear objetos complejos de distintas clases únicamente configurando el Builder.

A continuación definiremos el patrón de acuerdo a la plantilla que venimos usando en las entregas anteriores:

Constructor (Builder)


Nombre: Builder

Problema y Contexto:

Un único proceso de construcción debe ser capaz de construir distintos objetos complejos, abstrayéndonos de los detalles particulares de cada uno de los tipos.

Se aplica cuando:

  • Nuestro sistema trata con objetos complejos (compuestos por muchos atributos) pero el número de configuraciones es limitada.
  • El algoritmo de creación del objeto complejo puede independizarse de las partes que lo componen y del ensamblado de las mismas.


Solución y Estructura:

La solución será crear un constructor que permita construir todos los tipos de objetos, ayudándose de constructores concretos encargados de la creación de cada tipo en particular. Un objeto director será el encargado de coordinar y ofrecer los resultados.

La estructura es la siguiente:

https://upload.wikimedia.org/wikipedia/commons/thumb/f/f3/Builder_UML_class_diagram.svg/800px-Builder_UML_class_diagram.svg.png

Donde:

Director: Se encarga de construir un objeto utilizando el Constructor (Builder).

Builder: Interfaz abstracta que permite la creación de objetos.

Concrete Builder: Implementación concreta del Builder definida para cada uno de los tipos. Permite crear el objeto concreto recopilando y creando cada una de las partes que lo compone.

Product: Objeto que se ha construido tras el proceso definido por el patrón.

Consecuencias:

  • POSITIVAS:
    • Reduce el acoplamiento.
    • Permite variar la representación interna del objeto, respetando la clase builder. Es decir, conseguimos independizar la construcción de la representación.
  • NEGATIVAS:
    • Introduce complejidad en los programas.


Patrones Relacionados: Método Factoría (Factory Method)

Ejemplo:

Vamos a repasar los conceptos mediante un caso práctico en Java. Siguiendo la línea del artículo anterior, crearemos distintos tipos de coches (berlina, coupé y monovolúmen) abstrayéndonos de su representación.

En primer lugar definiremos el producto objeto. Fijarse en la manera de definir los setter, ésto es una buena práctica a la hora de asignar múltiples propiedades a la vez, ya que podremos hacerlo de la forma: coche.cilindrada(2000).potencia(300)...


public class Coche
{
private int cilindrada = 0;
private int potencia = 0;
private String tipo = “”;
private int num_asientos = 0.

public Coche cilindrada(int cilindrada)
{
this.cilindrada = cilindrada;
return this;
}

public Coche potencia(int potencia)
{
this.potencia = potencia;
return this;
}

public Coche tipo(String tipo)
{
this.tipo = tipo;
return this;
}

public Coche numAsientos(int num_asientos)
{
this.num_asientos = num_asientos;
return this;
}
}



A continuación crearemos un constructor abstracto capaz de construir todos los tipos de coche:


abstract class ConstructorCoches
{
protected Coche coche;

public void nuevo(){coche = new Coche();}
public Coche obtenerCoche(){return coche;}

public abstract void construirMotor();
public abstract void construirCarroceria();

}



El siguiente paso es definirlos Constructores concretos:


public class ConstructorCochesAudi extends ConstructorCoches
{
public void construirMotor()
{
cohe.cilindrada(2995).potencia(300);
}
public void construirCarroceria()
{
cohe.tipo(“Audi A7 Sportback 3.0 TFSI quattro S tronic 7 vel.”).num_asientos (5);
}
}
public class ConstructorCochesBMW extends ConstructorCoches
{
public void construirMotor()
{
cohe.cilindrada(4395).potencia(560);
}
public void construirCarroceria()
{
cohe.tipo(“BMW Serie 5 2016”).num_asientos (5);
}
}
public class ConstructorCochesTesla extends ConstructorCoches
{
public void construirMotor()
{
cohe.potencia(560);
}
public void construirCarroceria()
{
cohe.tipo(“Tesla Model S”).num_asientos (5);
}
}



Ahora toca especificar al Director, que será el que actuará de intermediario entre el usuario de los Constructores y los propios Constructores:


public class Concesionario
{
private ConstructorCoches constructorCoches;

public void establecerConstructor(ConstructorCoches cc){this.constructorCoches=cc;}
public void obtenerCoche(){return constructorCoches.obtenerCoche();}

public void construirCoche()
{
constructorCoches.nuevo();
constructorCoches.construirMotor();
constructorCoches.construirCarroceria();
}

}



Y para finalizar, un cliente que use el constructor:


public static void main(String[] args)
{
Concesionario director = new Concesionario();
ConstructorCoches constructor;
if(args[0].equals(“Audi”))
{
constructor = new ConstructorCochesAudi();
}
else if(args[0].equals(“BMW”))
{
constructor = new ConstructorCochesBMW();
}
else if(args[0].equals(“Tesla”))
{
constructor = new ConstructorCochesTesla();
}

director.establecerConstructor(constructor);
director.construirCoche();
Coche producto = director.obtenerCoche();
}

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP