Facade pattern: interfacce uniformi per i vostri progetti software
Chi ricerca delle strategie adatte a semplificare software particolarmente complessi si imbatte inevitabilmente nel facade design pattern o facade pattern. Assieme ad altri modelli, come il decorator pattern o il composite pattern, fa parte della categoria dei cosiddetti modelli strutturali GoF (abbreviazione di Gang of Four) che dal 1994, data della loro pubblicazione, plasmano il design dei software.
In questo articolo scoprite che cos’è esattamente il facade pattern e come questo aiuta gli sviluppatori ad alleggerire i sottosistemi.
Che cos’è il facade pattern?
Il facade design pattern è uno dei 23 GoF design pattern originariamente pubblicati 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 semplificare la creazione di software flessibili e riutilizzabili. Nello specifico, il facade pattern offre una soluzione per raggruppare con facilità le varie interfacce presenti all’interno dei sistemi più complessi.
Una classe facade universale, oltre a fungere da interfaccia, delega alcune importanti funzioni del software ai relativi sottosistemi, così da garantire la migliore gestione possibile delle relazioni tra le varie sottocomponenti di un programma.
Quali problemi risolve l’approccio del facade pattern?
I client che accedono a un sottosistema complesso utilizzano una moltitudine di oggetti con interfacce anche molto diverse tra loro o che comunque sono in una relazione di dipendenza con questi oggetti. Dal punto di vista dello sviluppatore, questo rende particolarmente difficoltoso implementare, modificare, testare e riusare i client. È qui che entra in gioco il facade design pattern.
Il modello facade prevede la definizione di un oggetto facade centrale (chiamato anche “façade”) che:
- implementa un’interfaccia universale per le singole interfacce dei sottosistemi;
- possa eseguire funzioni aggiuntive, qualora necessario, prima o dopo l’inoltro di una richiesta da parte del client.
Data la sua funzione di intermediario, l’oggetto facade fa sì che l’accesso e la comunicazione con le singole componenti di un sottosistema sia semplificata e la dipendenza diretta delle singole componenti minimizzata. Inoltre, esso delega le richieste al client, in modo che i client non debbano conoscere né le classi né le loro relazioni e dipendenze.
Facade pattern: diagramma di classe in UML del modello facade
La classe facade è l’unità strutturale decisiva del facade pattern. La sua implementazione ed elaborazione spetta allo sviluppatore che desidera semplificare la complessità del proprio software grazie all’utilizzo di questo pratico modello di design. Una volta applicato il modello, gli oggetti client coinvolti concentrano l’intera comunicazione sulla classe facade che diventa così l’unica istanza nel nuovo sistema che viene a crearsi, dalla quale i client sono direttamente dipendenti.
Il diagramma UML di seguito riportato serve a chiarire la relazione tra i client, l’oggetto facade e le classi del sottosistema 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 sottosistemi alla base del software, diminuendo così la complessità del sistema. Il suo approccio favorisce inoltre il principio del loose coupling o accoppiamento lasco. Il minor grado di dipendenza tra le singole componenti permette di apportare modifiche ed effettuare manutenzioni in qualsiasi momento senza particolari difficoltà, in quanto tali modifiche vengono per lo più eseguite a livello locale. Questo accoppiamento serve inoltre a rendere il sistema più facile da estendere.
Se i client necessitano di un accesso diretto a delle specifiche classi del sottosistema, questo può essere reso possibile anche con il modello del facade pattern. In questo caso la visibilità del sottosistema deve essere programmata in modo tale che, all’evenienza, il client possa trascurare il facade.
L’impiego del modello di design facade può tuttavia comportare anche degli svantaggi. A causa del suo ruolo centrale, l’implementazione di un facade è un’operazione molto impegnativa e complicata. Ancor di più, se lo si desidera inglobare in un codice precedentemente creato. La creazione di un’interfaccia facade corrisponde generalmente a un livello aggiuntivo di indirezione e al conseguente allungamento dei tempi per l’elaborazione dell’invocazione dei metodi e delle funzioni, per l’accesso alla memoria, ecc. Infine, il facade pattern cela il rischio che il software diventi troppo dipendente dall’interfaccia superiore principale.
Vantaggi | Svantaggi |
---|---|
Minimizza la complessità dei sottosistemi | Implementazione complicata (in modo particolare all’interno di un codice già esistente) |
Promuove il principio dell’accoppiamento lasco | L’approccio è legato a un ulteriore livello di indirezione |
Rende il software più flessibile e facilmente riutilizzabile | Maggiore dipendenza dall’interfaccia facade |
Facade design pattern: gli scenari d’impiego classici
Le caratteristiche del modello di design facade lo rendono interessante per numerosi scenari di utilizzo. Primo tra tutti, nel caso in cui si desideri disporre di un’interfaccia uniforme per l’accesso a sottosistemi complessi o a un numero qualsiasi di oggetti. Un facade garantisce una semplificazione notevole, motivo per il quale l’impiego di una strategia di facade pattern in fase di pianificazione del progetto dovrebbe giocare un ruolo di prim’ordine.
Un altro esempio tipico sono i software in cui si vuole minimizzare la dipendenza tra client e sottosistemi fondamentali.
Infine, l’approccio facade risulta valido se vi trovate a pianificare un progetto software che deve essere ripartito su più livelli. In questo caso, l’utilizzo di facade come interfacce di comunicazione tra i livelli fornisce maggiore flessibilità nel caso di estensioni e modifiche a posteriori delle componenti.
Esempio concreto di applicazione del facade pattern
Il facade design pattern è un modello di design che può essere utilizzato con diversi linguaggi di programmazione, tra cui C++, C#, JavaScript, Java, PHP e Python. L’esempio che segue, per il quale ci siamo ispirati al tutorial su tutorialspoint, utilizza un codice in Java.
Nell’esempio si vuole definire un’interfaccia per gli oggetti universalmente valida, chiamata “Shape”, in grado di rappresentare le forme geometriche. Inoltre, vengono generate delle classi concrete che implementano questa interfaccia, così come una classe facade, chiamata “ShapeMaker”, incaricata di delegare le richieste del client.
Per prima cosa creiamo l’interfaccia Shape.java con il codice seguente:
public interface Shape {
void draw();
}
Dopodiché passiamo alla creazione di Rectangle.java (classe per gli oggetti di forma rettangolare), Square.java (classe per gli oggetti quadrati) e Circle.java (classe per oggetti a forma di cerchio): tre classi concrete che implementano l’interfaccia.
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, integriamo la classe facade ShapeMaker nel codice, così che i client possano interagirci 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();
}
}