El Builder separa la construcción de un objeto complejo de su representación, de forma que el mismo proceso de construcción pueda crear diferentes representaciones.
La necesidad de crear un objeto complejo de manera flexible y controlada, evitando tener un constructor con una larga lista de parámetros, lo cual no es nada práctico.
La solución que propone el Builder es:
Este patrón es recomendable cuando el proceso de construcción:
Mayor control sobre el proceso de construcción: Permite una construcción paso a paso, lo que da un control más fino.
Encapsulamiento y Claridad: Encapsula el código de construcción en un solo lugar sin “ensuciar” el resto del código.
Reutilización del Objeto de Construcción: El objeto constructor puede ser reutilizado para crear distintas variantes del objeto.
Complejidad Adicional: Introduce más clases y objetos (director, builder, builderconcreto), lo que puede complicar el código.
Requiere Crear un Constructor Separado: Para cada tipo diferente de objeto es necesario un constructor diferente.
Estamos construyendo un sistema para configurar computadoras personalizadas.
Las computadoras pueden tener diferentes componentes (CPU, GPU, memoria, etc.), y queremos permitir al cliente elegir estas partes.
Los clientes deben poder crear una computadora a partir de la configuración de cada una de sus partes.
Implementamos un Builder que permite crear un objeto complejo (la computadora) a partir de la construcción de cada una de sus partes.
La interfaz ComputerBuilder define los pasos para ensamblar diferentes componentes de una computadora (CPU, GPU, memoria). GamingComputerBuilder es una implementación específica que ensambla una computadora gamer siguiendo esos pasos. Computer es la computadora ensamblada final, con los componentes seleccionados. ComputerShop actúa como el director, que guía el ensamblaje de la computadora mediante un ComputerBuilder.
Codificamos en Java lo que preparamos en el diagrama.
Definimos el Producto:
class Computer {
private String cpu;
private String gpu;
private String memory;
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public String getGpu() {
return gpu;
}
public void setGpu(String gpu) {
this.gpu = gpu;
}
public String getMemory() {
return memory;
}
public void setMemory(String memory) {
this.memory = memory;
}
}
Definimos la interfaz de construcción:
interface ComputerBuilder {
void buildCPU();
void buildGPU();
void buildMemory();
Computer getComputer();
}
Implementamos un constructor concreto para computadoras gamer:
class GamingComputerBuilder implements ComputerBuilder {
private Computer computer = new Computer();
public void buildCPU() {
computer.setCPU(“High-end CPU”);
}
public void buildGPU() {
computer.setGPU(“High-end GPU”);
}
public void buildMemory() {
computer.setMemory(“64GB RAM”);
}
public Computer getComputer() {
return computer;
}
}
Creamos el director, que utiliza el builder para construir la computadora:
class ComputerShop {
public Computer constructComputer(ComputerBuilder builder) {
builder.buildCPU();
builder.buildGPU();
builder.buildMemory();
return builder.getComputer();
}
}
Los participantes que vimos antes son: Builder, ConcreteBuilder, Product, Director:
Este ejemplo pudimos ver el uso del patrón Builder ensamblando computadoras con distintas especificaciones, de manera estructurada y flexible.
Cada componente, como la CPU, GPU o memoria, se selecciona y se ensambla, paso a paso, facilitando la personalización para el cliente, sin complicar el proceso de construcción del objeto final.
Las clases ConcreteBuilder suelen implementarse con métodos de fabricación (Factory Method).
Ambos se parecen en que construyen objetos complejos. El Builder retorna el objeto complejo como paso final, mientras que el Abstract Factory lo devuelve de inmediato.
Muchas veces lo que construye el Builder es un Composite.