Builder
Propósito
Separar la construcción de un objeto complejo de su representación para que el mismo proceso de
construcción pueda crear diferentes representaciones.
Explicación
Ejemplo real
Imagina un generador de personajes para un juego de rol. La opción más fácil es dejar que el ordenador
cree el personaje por ti. Si quieres seleccionar manualmente los detalles del personaje como
profesión, sexo, color de pelo, etc. la generación del personaje se convierte en un proceso paso a paso que
se completa cuando todas las selecciones están listas.
En pocas palabras
Permite crear diferentes sabores de un objeto evitando la contaminación del constructor. Útil
cuando puede haber varios sabores de un objeto. O cuando hay muchos pasos involucrados en la creación de un objeto.
creación de un objeto.
Wikipedia dice
El patrón constructor es un patrón de diseño de software de creación de objetos con la intención de encontrar
una solución al anti-patrón del constructor telescópico.
Dicho esto, permíteme agregar un poco sobre qué es el anti-patrón del constructor telescópico. En algún momento
u otro, todos hemos visto un constructor como el siguiente:
public Hero(Profession profession, String name, HairType hairType, HairColor hairColor, Armor armor, Weapon weapon) {
}
Como puedes ver, el número de parámetros del constructor puede salirse rápidamente de control, y puede volverse difícil
entender la disposición de los parámetros. Además, esta lista de parámetros podría seguir creciendo si quisieras agregar
más opciones en el futuro. A esto se le llama anti-patrón del constructor telescópico.
Ejemplo programático
La alternativa sensata es utilizar el patrón Builder. En primer lugar, tenemos a nuestro héroe Hero
que queremos
crear:
public final class Hero {
private final Profession profession;
private final String name;
private final HairType hairType;
private final HairColor hairColor;
private final Armor armor;
private final Weapon weapon;
private Hero(Builder builder) {
this.profession = builder.profession;
this.name = builder.name;
this.hairColor = builder.hairColor;
this.hairType = builder.hairType;
this.weapon = builder.weapon;
this.armor = builder.armor;
}
}
Luego tenemos al constructor:
public static class Builder {
private final Profession profession;
private final String name;
private HairType hairType;
private HairColor hairColor;
private Armor armor;
private Weapon weapon;
public Builder(Profession profession, String name) {
if (profession == null || name == null) {
throw new IllegalArgumentException("profession and name can not be null");
}
this.profession = profession;
this.name = name;
}
public Builder withHairType(HairType hairType) {
this.hairType = hairType;
return this;
}
public Builder withHairColor(HairColor hairColor) {
this.hairColor = hairColor;
return this;
}
public Builder withArmor(Armor armor) {
this.armor = armor;
return this;
}
public Builder withWeapon(Weapon weapon) {
this.weapon = weapon;
return this;
}
public Hero build() {
return new Hero(this);
}
}
Entonces se puede utilizar como:
var mage = new Hero.Builder(Profession.MAGE, "Riobard").withHairColor(HairColor.BLACK).withWeapon(Weapon.DAGGER).build();
Diagrama de clases
Aplicabilidad
Utiliza el patrón Builder cuando
- El algoritmo para crear un objeto complejo debe ser independiente de las partes que componen el objeto y cómo se
ensamblan. - El proceso de construcción debe permitir diferentes representaciones para el objeto que se construye.
Tutoriales
Usos en el mundo real
- java.lang.StringBuilder
- java.nio.ByteBuffer así como otros
buffers
como FloatBuffer, IntBuffer, etc. - java.lang.StringBuffer
- Todas las implementaciones
de java.lang.Appendable - Apache Camel builders
- Apache Commons Option.Builder