Il pattern Builder fa parte dei design pattern. Si tratta di modelli ben col­lau­da­ti che fa­ci­li­ta­no il lavoro di pro­gram­ma­zio­ne orientata agli oggetti, in quanto per­met­to­no agli svi­lup­pa­to­ri di non dover ripetere ogni volta i passaggi che si ripetono, dando loro la pos­si­bi­li­tà di usare una soluzione già definita. Questi elementi software risalgono al libro pub­bli­ca­to nel 1994 Design Patterns: elementi per il riuso di software a oggetti dei quattro svi­lup­pa­to­ri di software sta­tu­ni­ten­si co­no­sciu­ti come “la banda dei quattro” (in inglese “Gang of Four”, ab­bre­via­to in GoF).

In questo articolo della nostra guida vi pre­sen­tia­mo gli aspetti es­sen­zia­li dei modelli di builder design pattern, av­va­len­do­ci anche dell’aiuto di un esempio pratico.

Il builder pattern più nel dettaglio

Il builder fa parte del gruppo dei modelli di creazione co­no­sciu­to come design pattern. Migliora sia la sicurezza durante il processo di co­stru­zio­ne che la leg­gi­bi­li­tà del codice del programma. L’obiettivo dei modelli builder è di per­met­te­re la co­stru­zio­ne di un oggetto uti­liz­zan­do una classe helper invece che con i soliti co­strut­to­ri.

Citazione

“Separate the con­struc­tion of a complex object from its re­pre­sen­ta­tion so that the same con­struc­tion process can create different re­pre­sen­ta­tions.”

Tra­du­zio­ne: “Separare la co­stru­zio­ne di un oggetto complesso dalla sua rap­pre­sen­ta­zio­ne così che lo stesso processo di co­stru­zio­ne possa creare diverse rap­pre­sen­ta­zio­ni.” (Tra­du­zio­ne di IONOS)

– Gang of Four: Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides

Fonte: Design Patterns: Elements of Reusable Object-Oriented Software, casa editrice: Addison-Wesley Pro­fes­sio­nal; prima edizione (10 novembre 1994)

Nel builder design pattern si di­stin­guo­no quattro diversi attori:

  • Director: questo attore co­strui­sce l’oggetto complesso uti­liz­zan­do l’in­ter­fac­cia del co­strut­to­re. Conosce i requisiti della sequenza di lavoro del co­strut­to­re. È al livello del direttore che la co­stru­zio­ne di un oggetto viene di­sac­cop­pia­ta dal client.
  • Builder: il co­strut­to­re mette a di­spo­si­zio­ne un’in­ter­fac­cia per la co­stru­zio­ne delle com­po­nen­ti di un oggetto complesso (il prodotto).
  • Con­cre­te­Buil­der: questo attore si occupa dell’effettiva creazione delle parti dell’oggetto complesso, definendo e gestendo la rap­pre­sen­ta­zio­ne dell’oggetto, di­spo­nen­do anche di un’in­ter­fac­cia per l’output dell’oggetto.
  • Product: il risultato dell’attività del builder pattern, ossia l’oggetto complesso da costruire.

Tuttavia, il passaggio decisivo di questo pattern avviene a livello del direttore, dove la creazione di un oggetto/prodotto viene separata dal client.

Il builder pattern nella rap­pre­sen­ta­zio­ne UML

Per la rap­pre­sen­ta­zio­ne grafica dei processi di pro­gram­ma­zio­ne viene usato il lin­guag­gio di mo­del­la­zio­ne, più co­mu­ne­men­te chiamato UML (Unified Modeling Language). La grafica qui sotto mostra come il builder pattern sia composto da numerosi oggetti che in­te­ra­gi­sco­no tra loro.

Pro e contro del builder pattern

Vantaggi del Builder

La co­stru­zio­ne o creazione e la rap­pre­sen­ta­zio­ne (output) vengono isolate. Le rap­pre­sen­ta­zio­ni interne del co­strut­to­re vengono “nascoste” dal director. Nuove rap­pre­sen­ta­zio­ni possono essere fa­cil­men­te aggiunte grazie a nuove classi di co­stru­zio­ni concrete. Il processo di co­stru­zio­ne viene espli­ci­ta­men­te gestito dal director. Nel caso in cui si debbano applicare delle modifiche lo si può fare senza dover passare per i client.

Svantaggi del Builder

Data la stretta con­nes­sio­ne tra prodotto, Con­cre­te­Buil­der e le classi coinvolte nel processo di co­stru­zio­ne, può risultare difficile apportare modifiche al processo. La creazione degli oggetti richiede spesso una co­no­scen­za delle spe­ci­fi­che ap­pli­ca­zio­ni e del loro ambiente. L’utilizzo di pattern co­no­sciu­ti e del builder può portare i pro­gram­ma­to­ri a non ac­cor­ger­si di soluzioni più semplici e magari anche più eleganti. Il builder pattern è perciò uno dei design pattern meno im­por­tan­ti tra i pro­gram­ma­to­ri.

Dove viene impiegato il builder pattern?

Per rendere più intuitiva la spie­ga­zio­ne del builder pattern lo possiamo comparare alle dinamiche sem­pli­fi­ca­te di un ri­sto­ran­te, dove un cliente fa la propria or­di­na­zio­ne. Lo staff del ri­sto­ran­te, che qui cor­ri­spon­de ai vari attori, agisce alla ricezione dell’ordine al fine di servire al tavolo quanto richiesto. L’intero processo fino all’arrivo al tavolo del cibo ordinato da parte del cliente avviene dietro le quinte. Il cliente non vede cosa accade in cucina in seguito alla sua or­di­na­zio­ne, ma ne riceve solamente il risultato ultimo servito al tavolo. Nel lin­guag­gio di pro­gram­ma­zio­ne questo viene co­mu­ne­men­te de­no­mi­na­to “print”.

Le seguenti parti di codice pre­sen­ta­no tutti gli attori del builder pattern se­pa­ra­ta­men­te.

L’oggetto, il menu completo, è ini­zial­men­te vuoto; l’ordine lo riempie:

public class Menue {
	private String starter = "Nessun antipasto";
	private String maincourse = "Nessuna portata principale";
	private String dessert = "Nessun dolce";
	private String drink = "Nessuna bevanda";
	public void setVorspeise(String starter) {
		this.starter = starter;
	}
	public void setHauptgericht (String maincourse) {
		this.maincourse = maincourse;
	}
	public void setNachspeise(String dessert) {
		this.dessert = dessert;
	}
	public void setGetraenk(String drink) {
		this.drink = drink;
	}
	public void print() {
		System.out.println(
			"Il menu è pronto! " + "\n" +
			" – Antipasto: " + starter +
			" – Portata principale: " + maincourse +
			" – Dolce: " + dessert +
			" – Bevanda: " + drink);
	}
}

Il director prepara “l’ambiente” che permette la creazione di un menu da pre­sen­ta­re al cliente. Questo ambiente è ac­ces­si­bi­le a ogni cliente. Il cliente comunica esclu­si­va­men­te con il direttore, mentre l’effettiva pre­pa­ra­zio­ne avviene dietro le quinte:

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();
	}
}

A questo punto entra in azione il co­strut­to­re. Nell’esempio proposto si tratta dello chef del ri­sto­ran­te:

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

Il Con­cre­te­Buil­der, il cuoco del ri­sto­ran­te, cucina/co­strui­sce le singole com­po­nen­ti del menu ordinato. Così facendo so­vra­scri­ve (override) i punti del menu astratti e li so­sti­tui­sce quindi con le pietanze:

public class MenuOfTheDayBuilder extends MenuBuilder {
	@Override
	public void buildStarter() {
		burger.setStarter("Zuppa di zucca");
	}
	@Override
	public void buildMainCourse() {
		burger.setMainCourse("Manzo ai ferri con patatine fritte");
	}
	@Override
	public void buildDessert() {
		burger.setDessert("Gelato alla vaniglia");
	}
	@Override
	public void buildDrink() {
		burger.setDrink("Vino rosso della casa");
	}
}

Infine, vengono servite all’ospite le singole portate. Questo passaggio finale viene nominato “print” nell’ambito della pro­gram­ma­zio­ne:

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();
	}
}
N.B.
L’esempio qui usato si basa sui codici di Daniel Høyer Jacobsen, sul cui sito trovate il­lu­stra­ti diversi modelli di design pattern in Java.
Vai al menu prin­ci­pa­le