Patrón Builder

El patrón de fábrica es un patrón de diseño creacional que se utiliza para crear objetos de manera eficiente y efectiva.

El patrón de diseño Builder es un patrón de diseño creacional que se utiliza para construir objetos complejos paso a paso. Se separa la construcción de un objeto de su representación final, permitiendo que el mismo proceso de construcción pueda crear diferentes representaciones.

¿Cómo Funciona?

El patrón Builder funciona de la siguiente manera:

  • Director: La clase Director es la que orquesta la construcción del objeto. Sabe en qué orden llamar a los métodos del Builder para obtener el objeto final. No sabe los detalles de la construcción, solo cómo usar el Builder.

  • Builder: La interfaz Builder define los métodos para construir las diferentes partes del objeto. Estos métodos son abstractos y son implementados por los Concrete Builders.

  • Concrete Builder: Las clases Concrete Builder implementan la interfaz Builder. Se encargan de la construcción real de las partes del objeto y mantienen el estado de la construcción.

  • Producto: El Producto es el objeto complejo que se está construyendo. Sus partes se construyen en los Concrete

  • .

El cliente interactúa con el Director para iniciar la construcción. El Director utiliza un Builder para construir el objeto paso a paso y finalmente el Builder devuelve el objeto completo al cliente.

Ejemplo de Uso

Un ejemplo clásico es la construcción de una casa. Una casa es un objeto complejo con varias partes como paredes, puertas, ventanas, un techo, etc. Puedes tener diferentes tipos de casas (de madera, de ladrillo, de piedra) que, aunque tengan las mismas partes, se construyen con diferentes materiales.

  • Director: Un arquitecto que sabe el orden en que se construye una casa (primero los cimientos, luego las paredes, etc.).

  • Builder: Una interfaz "ConstructorDeCasa" con métodos como construirParedes(), construirPuertas(), construirTecho().

  • Concrete Builder: ConstructorCasaDeMadera y ConstructorCasaDeLadrillo. Cada uno implementa la interfaz de forma diferente para construir una casa de su respectivo material.

  • Producto: La Casa en sí misma, con sus propiedades como paredes, puertas, techo.

Ventajas

  • Construcción paso a paso: Permite construir objetos de forma incremental, lo que es útil para objetos complejos con muchas partes opcionales o con un orden de construcción específico.

  • Código más legible: El código de creación es más claro y legible porque cada paso de la construcción está en un método con un nombre descriptivo.

  • Separación de responsabilidades: Separa el código de la construcción del objeto del código del objeto en sí mismo, lo que facilita el mantenimiento y la modificación.

Desventajas

  • Aumento de la complejidad: Introduce varias clases (Director, Builder, Concrete Builders, Product), lo que puede ser excesivo para objetos simples.

  • Mayor código: Se requiere más código para implementar el patrón en comparación con un constructor simple.


Ejemplo de Código

JavaScript

// Producto: la bicicleta que se va a construir
class Bicicleta {
  constructor() {
    this.partes = {};
  }

  addParte(nombre, valor) {
    this.partes[nombre] = valor;
  }

  mostrar() {
    console.log("Bicicleta construida con las siguientes partes:");
    for (const parte in this.partes) {
      console.log(`- ${parte}: ${this.partes[parte]}`);
    }
  }
}

// Builder: la clase que construye la bicicleta
class BicicletaBuilder {
  constructor() {
    this.bicicleta = new Bicicleta();
  }

  // Métodos que construyen y devuelven el builder para encadenar
  conCuadro(tipo) {
    this.bicicleta.addParte('cuadro', tipo);
    return this;
  }

  conRuedas(tamano) {
    this.bicicleta.addParte('ruedas', tamano);
    return this;
  }

  conCesto() {
    this.bicicleta.addParte('cesto', 'instalado');
    return this;
  }

  conTimbre() {
    this.bicicleta.addParte('timbre', 'instalado');
    return this;
  }

  // Método final para obtener el producto terminado
  build() {
    return this.bicicleta;
  }
}

// Uso del patrón
const miBicicleta = new BicicletaBuilder()
  .conCuadro('aluminio')
  .conRuedas('29 pulgadas')
  .conCesto()
  .build();

miBicicleta.mostrar();

console.log('---');

const bicicletaDeCarreras = new BicicletaBuilder()
  .conCuadro('carbono')
  .conRuedas('700c')
  .conTimbre()
  .build();

bicicletaDeCarreras.mostrar();

Explicación del Código

  • La clase Bicicleta es nuestro Producto. Tiene un método addParte para agregar componentes y un método mostrar para ver la configuración final.

  • La clase BicicletaBuilder es nuestro Builder. Su constructor crea una nueva instancia de Bicicleta.

  • Los métodos como conCuadro, conRuedas, conCesto, y conTimbre son los "constructores" de partes. Cada uno añade una parte a la bicicleta y, crucialmente, devuelve this, la propia instancia de BicicletaBuilder. Esto es lo que permite el encadenamiento de métodos (.conCuadro(...).conRuedas(...)).

  • El método build() es el que finaliza la construcción y devuelve el objeto Bicicleta ya completo.

  • El código de uso demuestra cómo crear diferentes tipos de bicicletas (miBicicleta y bicicletaDeCarreras) utilizando el mismo proceso de construcción, pero con diferentes partes.

Este enfoque mejora la legibilidad y flexibilidad del código, especialmente cuando el objeto tiene muchas opciones de configuración.

Fuentes

Última actualización