Chi ricerca delle strategie adatte a sem­pli­fi­ca­re software par­ti­co­lar­men­te complessi si imbatte ine­vi­ta­bil­men­te nel facade design pattern o facade pattern. Assieme ad altri modelli, come il decorator pattern o il composite pattern, fa parte della categoria dei co­sid­det­ti modelli strut­tu­ra­li GoF (ab­bre­via­zio­ne di Gang of Four) che dal 1994, data della loro pub­bli­ca­zio­ne, plasmano il design dei software.

In questo articolo scoprite che cos’è esat­ta­men­te il facade pattern e come questo aiuta gli svi­lup­pa­to­ri ad al­leg­ge­ri­re i sot­to­si­ste­mi.

Che cos’è il facade pattern?

Il facade design pattern è uno dei 23 GoF design pattern ori­gi­na­ria­men­te pub­bli­ca­ti nel lontano 1994 come guida per lo sviluppo software dai quattro autori Erich Gamma, Ralph Johnson, Richard Helm e John Vlissides nel libro Design Patterns: Elements of Reusable Object-Oriented Software. Il principio generale di questi modelli consiste nel sem­pli­fi­ca­re la creazione di software fles­si­bi­li e riu­ti­liz­za­bi­li. Nello specifico, il facade pattern offre una soluzione per rag­grup­pa­re con facilità le varie in­ter­fac­ce presenti all’interno dei sistemi più complessi.

Una classe facade uni­ver­sa­le, oltre a fungere da in­ter­fac­cia, delega alcune im­por­tan­ti funzioni del software ai relativi sot­to­si­ste­mi, così da garantire la migliore gestione possibile delle relazioni tra le varie sot­to­com­po­nen­ti di un programma.

Quali problemi risolve l’approccio del facade pattern?

I client che accedono a un sot­to­si­ste­ma complesso uti­liz­za­no una mol­ti­tu­di­ne di oggetti con in­ter­fac­ce anche molto diverse tra loro o che comunque sono in una relazione di di­pen­den­za con questi oggetti. Dal punto di vista dello svi­lup­pa­to­re, questo rende par­ti­co­lar­men­te dif­fi­col­to­so im­ple­men­ta­re, mo­di­fi­ca­re, testare e riusare i client. È qui che entra in gioco il facade design pattern.

Il modello facade prevede la de­fi­ni­zio­ne di un oggetto facade centrale (chiamato anche “façade”) che:

  • im­ple­men­ta un’in­ter­fac­cia uni­ver­sa­le per le singole in­ter­fac­ce dei sot­to­si­ste­mi;
  • possa eseguire funzioni ag­giun­ti­ve, qualora ne­ces­sa­rio, prima o dopo l’inoltro di una richiesta da parte del client.

Data la sua funzione di in­ter­me­dia­rio, l’oggetto facade fa sì che l’accesso e la co­mu­ni­ca­zio­ne con le singole com­po­nen­ti di un sot­to­si­ste­ma sia sem­pli­fi­ca­ta e la di­pen­den­za diretta delle singole com­po­nen­ti mi­ni­miz­za­ta. Inoltre, esso delega le richieste al client, in modo che i client non debbano conoscere né le classi né le loro relazioni e di­pen­den­ze.

Facade pattern: diagramma di classe in UML del modello facade

La classe facade è l’unità strut­tu­ra­le decisiva del facade pattern. La sua im­ple­men­ta­zio­ne ed ela­bo­ra­zio­ne spetta allo svi­lup­pa­to­re che desidera sem­pli­fi­ca­re la com­ples­si­tà del proprio software grazie all’utilizzo di questo pratico modello di design. Una volta applicato il modello, gli oggetti client coinvolti con­cen­tra­no l’intera co­mu­ni­ca­zio­ne sulla classe facade che diventa così l’unica istanza nel nuovo sistema che viene a crearsi, dalla quale i client sono di­ret­ta­men­te di­pen­den­ti.

Il diagramma UML di seguito riportato serve a chiarire la relazione tra i client, l’oggetto facade e le classi del sot­to­si­ste­ma durante l’utilizzo del facade pattern.

Facade pattern: vantaggi e svantaggi

I punti di forza del facade design pattern sono chiari: l’oggetto facade “nasconde” i sot­to­si­ste­mi alla base del software, di­mi­nuen­do così la com­ples­si­tà del sistema. Il suo approccio favorisce inoltre il principio del loose coupling o ac­cop­pia­men­to lasco. Il minor grado di di­pen­den­za tra le singole com­po­nen­ti permette di apportare modifiche ed ef­fet­tua­re ma­nu­ten­zio­ni in qualsiasi momento senza par­ti­co­la­ri dif­fi­col­tà, in quanto tali modifiche vengono per lo più eseguite a livello locale. Questo ac­cop­pia­men­to serve inoltre a rendere il sistema più facile da estendere.

N.B.

Se i client ne­ces­si­ta­no di un accesso diretto a delle spe­ci­fi­che classi del sot­to­si­ste­ma, questo può essere reso possibile anche con il modello del facade pattern. In questo caso la vi­si­bi­li­tà del sot­to­si­ste­ma deve essere pro­gram­ma­ta in modo tale che, all’evenienza, il client possa tra­scu­ra­re il facade.

L’impiego del modello di design facade può tuttavia com­por­ta­re anche degli svantaggi. A causa del suo ruolo centrale, l’im­ple­men­ta­zio­ne di un facade è un’ope­ra­zio­ne molto im­pe­gna­ti­va e com­pli­ca­ta. Ancor di più, se lo si desidera inglobare in un codice pre­ce­den­te­men­te creato. La creazione di un’in­ter­fac­cia facade cor­ri­spon­de ge­ne­ral­men­te a un livello ag­giun­ti­vo di in­di­re­zio­ne e al con­se­guen­te al­lun­ga­men­to dei tempi per l’ela­bo­ra­zio­ne dell’in­vo­ca­zio­ne dei metodi e delle funzioni, per l’accesso alla memoria, ecc. Infine, il facade pattern cela il rischio che il software diventi troppo di­pen­den­te dall’in­ter­fac­cia superiore prin­ci­pa­le.

Vantaggi Svantaggi
Minimizza la com­ples­si­tà dei sot­to­si­ste­mi Im­ple­men­ta­zio­ne com­pli­ca­ta (in modo par­ti­co­la­re all’interno di un codice già esistente)
Promuove il principio dell’ac­cop­pia­men­to lasco L’approccio è legato a un ulteriore livello di in­di­re­zio­ne
Rende il software più fles­si­bi­le e fa­cil­men­te riu­ti­liz­za­bi­le Maggiore di­pen­den­za dall’in­ter­fac­cia facade

Facade design pattern: gli scenari d’impiego classici

Le ca­rat­te­ri­sti­che del modello di design facade lo rendono in­te­res­san­te per numerosi scenari di utilizzo. Primo tra tutti, nel caso in cui si desideri disporre di un’in­ter­fac­cia uniforme per l’accesso a sot­to­si­ste­mi complessi o a un numero qualsiasi di oggetti. Un facade ga­ran­ti­sce una sem­pli­fi­ca­zio­ne notevole, motivo per il quale l’impiego di una strategia di facade pattern in fase di pia­ni­fi­ca­zio­ne del progetto dovrebbe giocare un ruolo di prim’ordine.

Un altro esempio tipico sono i software in cui si vuole mi­ni­miz­za­re la di­pen­den­za tra client e sot­to­si­ste­mi fon­da­men­ta­li.

Infine, l’approccio facade risulta valido se vi trovate a pia­ni­fi­ca­re un progetto software che deve essere ripartito su più livelli. In questo caso, l’utilizzo di facade come in­ter­fac­ce di co­mu­ni­ca­zio­ne tra i livelli fornisce maggiore fles­si­bi­li­tà nel caso di esten­sio­ni e modifiche a po­ste­rio­ri delle com­po­nen­ti.

Esempio concreto di ap­pli­ca­zio­ne del facade pattern

Il facade design pattern è un modello di design che può essere uti­liz­za­to con diversi linguaggi di pro­gram­ma­zio­ne, tra cui C++, C#, Ja­va­Script, Java, PHP e Python. L’esempio che segue, per il quale ci siamo ispirati al tutorial su tu­to­rial­spoint, utilizza un codice in Java.

Nell’esempio si vuole definire un’in­ter­fac­cia per gli oggetti uni­ver­sal­men­te valida, chiamata “Shape”, in grado di rap­pre­sen­ta­re le forme geo­me­tri­che. Inoltre, vengono generate delle classi concrete che im­ple­men­ta­no questa in­ter­fac­cia, così come una classe facade, chiamata “Sha­pe­Ma­ker”, in­ca­ri­ca­ta di delegare le richieste del client.

Per prima cosa creiamo l’in­ter­fac­cia Shape.java con il codice seguente:

public interface Shape {
	void draw();
}

Dopodiché passiamo alla creazione di Rectangle.java (classe per gli oggetti di forma ret­tan­go­la­re), Square.java (classe per gli oggetti quadrati) e Circle.java (classe per oggetti a forma di cerchio): tre classi concrete che im­ple­men­ta­no l’in­ter­fac­cia.

public class Rectangle implements Shape {
	@Override
	public void draw() {
		System.out.println("Rectangle::draw()");
	}
}
public class Square implements Shape {
	@Override
	public void draw() {
		System.out.println("Rectangle::draw()");
	}
}
public class Circle implements Shape {
	@Override
	public void draw() {
		System.out.println("Rectangle::draw()");
	}
}

Infine, in­te­gria­mo la classe facade Sha­pe­Ma­ker nel codice, così che i client possano in­te­ra­gir­ci per creare le varie forme:

public class ShapeMaker {
	private Shape circle;
	private Shape rectangle;
	private Shape square;
	public ShapeMaker() {
		circle = new Circle();
		rectangle = new Rectangle();
		square = new Square();
	}
	public void drawCircle(){
		circle.draw();
	}
	public void drawRectangle(){
		rectangle.draw();
	}
	public void drawSquare(){
		square.draw();
	}
}
Vai al menu prin­ci­pa­le