Builders
Tags: java
Published: 2022-04-26 05:07:48

---
title: Builders
published: true
date: 2022-03-03 00:00:00 UTC
tags: java
canonical_url: https://jorge.aguilera.soy/blog/effective-java/2-builders.html
---

En el [post](1-constructors.html) anterior vimos cómo usar Factorias y las ventajas que estas pueden aportar sobre los constructores

En este post vamos a ver otra forma de construir objetos, los Builders.

## "Consider a builder when faced with many constructor parameters"

Tanto el uso de factorías como el de constructores tienen un problema cuando el número de parámetros para construir una clase empieza a ser elevado

<dl>
<dt>NOTE</dt>
<dd>
<p>Y cúando es elevado? pues cada cual tendrá su opinión pero en mi opinión más de tres parámetros ya es una
señal de que esa clase va a necesitar más bien pronto que tarde otro parámetro más y sería buena idea aplicar
un Builder</p>
</dd>
<dt>INFO</dt>
<dd>
<p>Cuando, tanto con factorías como constructores, empiezas a crear métodos con parámetros necesarios y
luego otros métodos en los que vas añadiendo cada vez un parámetro opcional se llama "telescoping constructor"</p>
</dd>
</dl>

```
class A{
    public static A newInstance(){
        return new A();
    }
    public static A newInstance(String nombre){
        return new A(nombre);
    }
    public static A newInstance(String nombre, int edad){
        return new A(nombre, edad...);
    }
    public static A newInstance(String nombre, int edad, Date nacimiento){
        return new A(nombre, edad...);
    }
    public static A newInstance(String nombre, int edad, Date nacimiento, Ciudad ciudad){
        return new A(nombre, edad...);
    }
    ...
}
```

Otra forma de inicializar objetos cuando el número de parámetros es numeroso es aplicando la aproximación de `JavaBeans`creando métodos get/set para cada propiedad de la instancia. Sin embargo esta forma tiene muchos problemas como por ejemplo la validación de que todos los parámetros han sido proporcionados, es muy "verbose", dificil de seguir y no puede crear objetos inmutables.

## Builder

Por todo ello el otro patrón que se aplica es creando un `Builder`

```
class A{

    private final int prp1;
    private final int prp2;
    ...
    private final int prpn;

    public int getPrp1() { return prp1;}
    // NO tenemos metodo setPrp1

    public static class Builder{
        private final int prp1;
        private final int prp2;
        ...
        private final int prpn;

        public Builder(){}

        public Builder prp1(int p){ prp1 = p; return this;}
        ...
        public Builder prpn(int p){ prpn = p; return this;}

        public A build(){
            // validar que tenemos todos los parametros necesarios
            return new A(this);
        }
    }
    private A(Builder builder){
        prp1 = builder.prp1;
        ...
        prpn = builder.prpn;
    }
}
```

y el código para crear una instancia A sería:

```
A a = new A.Builder().prpn(n).prp2(2).prp1(1).build();
```

<dl>
<dt>TIP</dt>
<dd>
<p>Si por ejemplo la clase requiere de unos parámetros requeridos es fácil pedirlos
en el constructor del Builder y declarar así explicitamente que son necesarios.</p>
</dd>
</dl>

## "The Builder pattern is well suited to class hierarchies"

Esta capacidad del patrón Builder no es fácil de ver de primeras (al menos a mí) pero es muy potente

Cuando tenemos una jerarquía de objetos tipo clase base "A" y otras clases que extienden de ella, "B" y "C", podemos aplicar el patrón Builder usando genéricos de tal forma que reutilizemos al máximo los builders

```
public abstract class A{

    abstract static class Builder<T extends Builder<T>>{

        public Builder(){
        }

        public T prp1(int prp1){
            this.prp1 = prp1;
            return self();
        }

        abstract A build();

        protected abstract T self();
    }

    private A(Builder<?> builder){
        // copio los atributos de A
    }

}

public class B extends A{

    public static class Builder extends A.Builder<Builder>{

        public Builder(){
        }

        @Override public B build(){
            return new B(this)
        }

        public T prp2(int prp2){
            this.prp2 = prp2;
            return self();
        }

        @Override protected Builder self(){ return this;}
    }

    private B(Builder builder){
        // copio los atributos de B
    }
}
```

El "truco" se encuentra en el Generic de la clase A: `Builder<T extends Builder<T> >` así como en el método`self`. Este es usado internamente por el builder para permitir al compilador poder concatenar las llamadas

`A a = new B.Builder().prp1(1).prp2(2).build`