¿Qué es el patrón de diseño Builder? 👷

Publicado el 09.07.2023 a las 22:03

¿Qué es el patrón de diseño Builder? 👷

  1. ¿Qué es el patrón de diseño Builder?

  2. ¿Qué es el anti patrón de constructor telescópico?

    • anti patrón de constructor telescópico con varios constructores

    • anti patrón de constructor telescópico con un constructor y múltiples parámetros

  3. ¿Cuando utilizar el patrón de diseño Builder?

  4. Implementando el patrón de diseño Builder

  5. Implementando el patrón de diseño Builder con JavaScript

Logo de fjmduran

¿Qué es el patrón de diseño Builder?

El patrón de diseño Builder es un patrón creacional que se utiliza para construir objetos complejos.


Permite separar la construcción de un objeto de su representación, de modo que el mismo proceso de construcción pueda crear diferentes representaciones.


Seguro que lo primero que se te viene a la cabeza es usar para este caso varios constructores, pero cuando el objeto a crear tiene una gran cantidad de opciones implicaría:


  • Muchos constructores
  • Un constructor con muchos parámetros

Dicho con palabras sencillas, el patrón de diseño builder nos permite crear diferentes tipos de un objeto evitando la contaminación del constructor o la creación de múltiples constructores, lo que conocemos como anti patrón de constructor telescópico (telescoping constructor anti-pattern).

¿Qué es el anti patrón de constructor telescópico?

El anti patrón constructor telescópico (telescoping constructor) se da cuando una clase tiene múltiples constructores con diferentes combinaciones de parámetros, lo que lleva a una serie de constructores sobrecargados y difíciles de mantener.


Vamos a verlo con un ejemplo, ayudará a entenderlo mejor.


Imagina que quieres tener una clase que instancie objetos pizza 🍕, el anti patrón de constructor telescópico se podría dar de dos formas:


  • Programando la clase con varios constructores
  • Programando la clase con un constructor con varios parámetros

anti patrón de constructor telescópico con varios constructores

//C#, Java...

public class Pizza {
    private string tamaño;
    private bool conPiña;
    private bool conAnchoas;   
    // ... todos los ingredientes que imagines
        
    public Pizza(string tamaño) {
        this.tamaño=tamaño;
    }
                    
    public Pizza(string tamaño, bool conPiña) {
        this.tamaño=tamaño;
        this.conPiña=conPiña;
    }
                    
    public Pizza(string tamaño, bool conPiña, bool conAnchoas) {
        this.tamaño=tamaño;
        this.conPiña=conPiña;
        this.conAnchoas = conAnchoas
    }         
    // ...
}                    
                

Como puedes ver, el número de constructores se puede ir rápidamente de las manos.


Además, esta lista de constructores podría seguir creciendo si quisieras añadir más opciones en el futuro.

anti patrón de constructor telescópico con un constructor y múltiples parámetros

//C#, Java...

public class Pizza {
    private string tamaño;
    private bool conPiña;
    private bool conAnchoas;    
    // ... todos los ingredientes que imagines
                    
    public Pizza(string tamaño, bool conPiña = false, bool conAnchoas = false, //...) {
        this.tamaño=tamaño;
        this.conPiña=conPiña;
        this.conAnchoas = conAnchoas

        // ...
    }        
}                    
                

Como puedes ver, el número de parámetros del constructor se puede ir rápidamente de las manos y puede resultar difícil entender la disposición de los parámetros.


Además, esta lista de parámetros podría seguir creciendo si quisieras añadir más opciones en el futuro.

¿Cuando utilizar el patrón de diseño Builder?

Debes de utilizar el patrón de diseño builder cuando vayas a tener distintas opciones para un mismo objeto, evitando el constructor telescoping.


La diferencia clave con el patrón de diseño Factory es que el patrón Factory se utiliza cuando la creación es un proceso de un solo paso, mientras que el patrón Builder se utiliza cuando la creación es un proceso de varios pasos.


Te dejo enlace a mi artículo donde hablaba sobre el patrón de diseño Factory 🔥

Imagen del artículo

¿Qué es el patrón de diseño Factory? 🦺

Te explico el patrón de diseño Factory con una analogía y ejemplos

Implementando el patrón de diseño Builder

Para implementar el patrón de diseño Builder con nuestro ejemplo de la clase pizza, lo primero que haremos será inyectar en la clase pizza un objeto builder cuya clase PizzaBuilder definiremos posteriormente:

//C#, Java...
  
public class Pizza {   
                      
    constructor(builder) {
        this.tamaño=builder.tamaño;
        this.conPiña=builder.conPiña || false;
        this.conAnchoas = builder.conAnchoas || false;  
        // ...
    }        
}                    
                  

A continuación definimos la clase PizzaBuilder

//C#, Java...
  
public class PizzaBuilder {   
                      
    constructor(tamaño) {
        this.tamaño=tamaño;        
    }  
    
    addPiña(){
        this.conPiña = true;
    }

    addAnchoas(){
        this.conAnchoas = true;
    }
    
    // ...

    build() {
        return new Pizza(this)
    }
}                    
                  

Cuando querramos instanciar un objeto pizza lo haremos:

//C#, Java...
    
const pizza = (new PizzaBuilder('Familiar'))
    .addPiña()
    .addAnchoas()
    .build()             
                    

Implementando el patrón de diseño Builder con JavaScript

El caso de JavaScript nos permite implementar el patrón de diseño Builder con muy poco código.


Cuando te encuentres que el número de argumentos de una función o método son demasiados (normalmente más de 2 argumentos se considera demasiado), utiliza un objeto como único argumento en lugar de múltiples argumentos.


Esto tiene dos propósitos:

  • Hace que el código parezca menos desordenado, ya que sólo hay un argumento.
  • No tienes que preocuparte por el orden de los argumentos, ya que ahora se pasan como propiedades con nombre del objeto.

Veamos el código, si tenemos la clase pizza así:

  
public class Pizza {

    private string tamaño;
    private bool conPiña;
    private bool conAnchoas;    
    // ... todos los ingredientes que imagines
                            
    public Pizza(string tamaño, bool conPiña = false, bool conAnchoas = false, //...) {
        this.tamaño=tamaño;
        this.conPiña=conPiña;
        this.conAnchoas = conAnchoas
        
        // ...
    }        
}                
                  

En lugar de instanciar una pizza así:

❌ const pizza = new Pizza('Familiar', true, false, ...)
        

Hazlo así:

✅ const burger = new Burger({
        tamaño : 'Familiar',
        conPiña : true,
        conAnchoas : false,
        //...
})
        

Hasta luego 🖖