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

El Builder Pattern es un tipo de plantilla de patrón de diseño que sirve para resolver tareas de programación en una programación orientada a objetos. Los patrones Builder (o Constructor) facilitan a los desarrolladores el proceso de programación porque no han de rediseñar cada paso que se repite como una rutina de programa.

En vez de rediseñar cada paso, pueden utilizar una solución establecida. Los elementos de software se basan en el libro Design Pattern: Elements of Reusable Object-Oriented Software publicado en 1994 por cuatro desarrolladores de software estadounidenses conocidos como la Gang of Four, o GoF para abreviar. En esta guía te presentamos los aspectos principales del patrón de diseño Builder e incluimos un ejemplo práctico.

El Builder Pattern en detalle

El Builder Pattern forma parte del grupo de patrones de construcción de los patrones de diseño. Mejora tanto la seguridad de construcción como la legibilidad del código del programa. El objetivo del patrón de diseño Builder es crear un objeto sin constructores conocidos pero con una clase auxiliar.

Cita

“Separar la construcción de un objeto complejo de su representación para que ese mismo proceso de construcción pueda crear diferentes representaciones.”

Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (Gang of Four)

Fuente: Design Patterns: Elements of Reusable Object-Oriented Software, 1ª edición, Ed. Addison-Wesley Professional (10 de noviembre de 1994).

Un patrón de diseño Builder distingue entre cuatro actores:

  • Director: este actor construye el objeto complejo con la interfaz del constructor. Es consciente de los requisitos de secuencia del constructor. Con el director, se desvincula la construcción del objeto del cliente.
  • Builder: ofrece una interfaz para crear los componentes de un objeto (o producto) complejo.
  • Specific builder: crea las partes del objeto complejo, define (y gestiona) la representación del object, y mantiene la interfaz de salida del objeto.
  • Producto: es el resultado de la “actividad” del Builder Pattern, es decir, el objeto que se construye.

El director supervisa el proceso decisivo del patrón Builder: la separación de la creación de un objeto/producto del cliente.

El Builder Pattern como diagrama UML

El lenguaje unificado de modelado, UML por las siglas en inglés de Unified Modelling Language, es útil para representar los procesos de programación gráficamente. Este gráfico muestra que el patrón de diseño Builder consta de varios objetos que interactúan los unos con los otros.

Puntos fuertes y débiles del patrón Builder

A continuación, mostramos las ventajas e inconvenientes de este patrón de diseño.

Ventajas del patrón de diseño Builder

La construcción y la representación (salida) se incorporan por separado. Las representaciones internas del constructor están ocultas para el director. Las nuevas representaciones como tal pueden integrarse fácilmente utilizando clases de constructores concretos. El proceso de construcción lo controla explícitamente el director. Si hay que hacer cambios, pueden hacerse sin consultar al cliente.

Inconvenientes de Builder

El patrón Constructor consta de un fuerte vínculo entre el producto, el constructor específico y las clases del proceso de diseño, así que puede ser difícil hacer cambios en el proceso básico. La construcción de los objetos requiere conocer su uso y su entorno concretos. Utilizar patrones conocidos, como el patrón de diseño Builder, puede hacer que los programadores pasen por alto soluciones más sencillas y elegantes. En el fondo, muchos desarrolladores consideran que este es uno de los patrones de diseño menos importantes.

¿Cuándo se utiliza el Builder Pattern?

Una manera de ilustrar el patrón de diseño Builder es considerando el ejemplo de un restaurante al que un cliente realiza un pedido. Una vez que han recibido el pedido, los cocineros actúan para elaborarlo. Todo el proceso hasta la entrega como tal se hace “entre bambalinas”; el cliente no ve lo que ocurre en la cocina y solo recibe el resultado (el print en lenguaje de programación).

El código que mostramos a continuación es un ejemplo que pone de manifiesto el papel de los actores individuales del Builder Pattern.

El objeto, es decir, el menú, está vacío al principio. Una vez se hace la comanda, se añade contenido.

public class Menu {
	private String starter = "No entrante";
	private String maincourse = "No plato principal";
	private String dessert = "No postre";
	private String drink = "No bebida";
	public void setentrante (String starter) {
		this.starter = starter;
	}
	public void setplatoprincipal (String maincourse) {
		this.maincourse = maincourse;
	}
	public void setpostre(String dessert) {
		this.dessert = dessert;
	}
	public void setbebida(String drink) {
		this.drink = drink;
	}
	public void print() {
		System.out.println(
			"¡Tu comida esta lista! " + "\n" +
			" – Entrante: " + starter +
			" – Plato principal: " + maincourse +
			" – Postre: " + dessert +
			" – Bebida: " + drink);
	}
}

El director proporciona el “ambiente” necesario para que un plato pueda ser elaborado (o construido) para el cliente. Este ambiente es accesible para todos los clientes. El cliente solo se comunica con el director para que la preparación como tal esté oculta:

public class MattsRestaurant {
	private MenuBuilder menuBuilder;
	public void setBuilder(MenuBuilder menuBuilder) {
		this.menuBuilder = menuBuilder;
	}
	public Menu buildMenu(){
		menuBuilder.buildStarter();
		menuBuilder.buildMainCourse();
		menuBuilder.buildDessert();
		menuBuilder.buildDrink();
		return menuBuilder.build();
	}
}

Luego, entra en escena el constructor. En nuestro ejemplo, sería el cocinero jefe:

public abstract class MenuBuilder {
	Menu menu = new Menu();
	abstract void buildStarter();
	abstract void buildMainCourse();
	abstract void buildDessert();
	abstract void buildDrink();
	Menu build()
{
		return menu;
	}
}

El constructor específico, en este caso el cocinero, construye (es decir, cocina) los componentes individuales del plato de la comanda. Para ello, ignora (override) los artículos del menú “abstract”:

public class MenuOfTheDayBuilder extends MenuBuilder {
	@Override
	public void buildStarter() {
		burger.setStarter("Sopa de calabaza");
	}
	@Override
	public void buildMainCourse() {
		burger.setMainCourse("Filete a la plancha con patatas");
	}
	@Override
	public void buildDessert() {
		burger.setDessert("Helado de vainilla");
	}
	@Override
	public void buildDrink() {
		burger.setDrink("Vino tinto");
	}
}

Por último, se resumen los componentes individuales del plato y se realiza la entrega al cliente, es decir, “se imprime”.

public class Main {
	public static void main(String[] args) {
		MattsRestaurant mattsRestaurant = new MattsRestaurant();
		menuRestaurant.setBuilder(new MenuOfTheDayBuilderBuilder());
		buildMenu(menuRestaurant);
		menuRestaurant.setBuilder(new SpecialMenuBuilder());
		buildMenu(menuRestaurant);
	}
	private static void buildMenu(MattsRestaurant mattsRestaurant) {
		MenuOfTheDay menu = mattsRestaurant.buildMenu();
		menu.print();
	}
}
Nota

Este ejemplo se basa en el código de Daniel Høyer Jacobsen, que está disponible en su página web Design Patterns in Java.