Facade Pattern

_Logo E' forse il pattern più comune tanto che il suo utilizzo passa inosservato. Riguarda la semplificazione di un insieme di interfacce, chiamato subsystem, tramite un’unica interfaccia. Sostanzialmente parliamo di definire un wrapper affinché l'utilizzo di un codice sia semplice ed immediato. Lo scopo è nascondere la complessità.

Un esempio molto reale riguarda il servizio clienti di un’azienda: esso è un Facade dei vari reparti che possono intervenire per prestare assistenza (amministrazione, magazzino, servizio tecnico…).

Ecco la definizione ufficiale da parte della Gang of Four, estratta dal testo Design Patterns Elements of Reusable Object-Oriented Software:

Fornire un’interfaccia unificata ad un insieme di interfacce di un sotto sistema (subsystem). Il Facade definisce un interfaccia di alto livello che rende il sotto insieme facile da utilizzare.

Si parla dei seguenti partecipanti:

  • Il Facade:
    • Viene utilizzato da un client per svolgere un determinato compito.
    • Delega opportunamente tale compito agli oggetti del sotto insieme.
  • Il Subsystem, formato da più oggetti:
    • Tali sotto oggetti gestiscono il lavoro assegnato dal Facade.
    • Non hanno alcuna conoscenza ne riferimento al Facade.

La problematiche principale riguarda l’identificare il sotto insieme, che può essere un codice in cui diversi oggetti interagiscono tra loro oppure il codice necessario all’utilizzo di una libreria oppure un API particolarmente complessa. In tutti i casi il Facade creato espone ciò che realmente serve al client.

L’esempio classico è il seguente:

  • Ho un client che utilizza tre oggetti per accedere a vari servizi in un determinato blocco di codice, necessario per completare un compito.
  • I tre oggetti vengono usati in quel punto ed interagiscono tra loro al fine di ottenere un risultato specifico.
  • Possono estrarre quel blocco di codice (e il riferimento ai tre oggetti) e creare un Facade che avrà, in questo caso, un metodo che genera il risultato voluto.
  • Internamente il Facade utilizzerà i tre oggetti nello stesso modo in cui venivano utilizzati dal client.
  • Il client avrà solo la dipendenza con il Facade e il Facade avrà la dipendenza ai tre oggetti.
  • Quel Facade potrà essere utilizzato altrove per ottenere lo stesso risultato.
  • L’implementazione interna del Facade potrebbe cambiare senza intaccare il client.
  • Il Client non avrà però accesso diretto alle altre funzionalità nascoste dal Facade.

Questi gli intenti di questo Pattern della categoria strutturale:

  • Fornire una interfaccia semplificata ad un codice più complesso.
  • Rendere il codice complesso più semplice da utilizzare.
  • Esporre un insieme di iterazioni tra oggetti complessi tramite una singola interfaccia.
  • Avvolgere un’API generica in un’interfaccia più semplice.
  • Avvolgere un’API mal progettata in un’interfaccia migliore.

Semplificare un blocco di codice complesso significa:

  • Semplificare il client, perché una parte del suo codice può essere spostato del Facade.
  • Individuare correttamente le reali dipendenze che ha il client: se passo al client un oggetto complesso di cui in realtà servono pochi membri, allora creo un'inutile dipendenza o peggio una catena di dipendenze.

Interessanti e corretti i quattro tipici utilizzi del Facade riportati su Wikipedia:

  • Un’interfaccia semplice è richiesta per accedere ad un sistema complesso.
  • Le astrazioni e le implementazione di un sotto sistema sono strettamente legate.
  • E’ richiesto un punto di entrata per ogni livello di un software stratificato (n-layer).
  • Un sistema è molto complesso e difficile da capire.

Proprio per questo suo obiettivo dedicato alla semplificare, il Facade Pattern viene spesso usato in fase di refactoring. Si possono infatti identificare le parti di codice che utilizzano un insieme di oggetti, altrove non utilizzati, e verificare se è possibile estrarre quel codice in un Facade. Il risultato è un client decisamente più snello, più facile da capire e da testare.

Questo pattern permette di far rispettare alcuni principi dell’OOP, come l’incapsulamento, il disaccoppiamento e l’astrazione. Parliamo quindi dei classici principi SOLID, in particolare ISP e DIP.

Spesso il Facade viene usato per eseguire il wrapper di servizi complessi o librerie. Usare un wrapper consente di chiarire cosa effettivamente viene utilizzato e di applicare il principio DIP: ciò permette di semplificare il cambio del servizio o della libreria e per lo stesso motivo semplifica il test (posso creare una implementazione fittizia).

Nel corso PluralSight dedicato a al Facade viene proposto un bel esempio relativo all’uso di Lucene.Net:

  • Un un’unica interfaccia (ISearchEngine) espone un unico metodo di ricerca (Search che riceve i le parole chiavi da cercare).
  • ISearchEngine è l’astrazione implementata dai Facade, come LuceneSearchEngine che è un sistema di ricerca complesso che utilizza Lucene.
  • Come spesso accade il Facade è accompagnato da classi di supporto (classi collaboratrici), nell’esempio RawSearchResult per evitare di utilizzare specifici tipi di una libreria piuttosto che di un’altra.
  • In ogni momento posso sostituire l’implementazione di ISearchEngine con un’altra libreria.

Conseguenze del Facade Pattern:

  • Semplificazione del client e quindi maggiore comprensività e testabilità.
  • In base agli aggiornamenti del sotto sistema, può essere necessario aggiornare il Facade (in alternativa se ne può creare un altro).
  • Semplificare significa anche limitare l’accesso alle funzionalità complete del sotto sistema (anche in questo caso è possibile creare più Facade).
  • Se un sotto insieme viene riutilizzato più volte, allora il riuso del Facade evitare duplicazione.
  • Favorisce la composizione piuttosto che la derivazione.

Una possibile alternativa al Facade Pattern è l’Abstract Factory, che ha sempre lo scopo di nascondere un insieme di classi.

Riferimenti:

  • DOFactory: due semplici ma esplicativi esempi in C#.
  • Wikipedia: spiegazione chiara accompagnata da due esempi in C#.
  • SourceMaking: ottima spiegazione con esempi in diversi linguaggi.
  • CodeProject: spiegazione ed esempi molto pratici.
  • Visual Studio Magazine: pratico esempio dedicato alla composizione di un… motore.

Infine, come discusso in un altro articolo, non bisogna confondere lo scopo del Facede Pattern con quello di pattern simili come l’Adapter Pattern, il Proxy o il Decorator.

Tag: Facade Pattern, OOP, Design Pattern