Gegeben sei die Modellierung einer Firmenverwaltung. Die Verwaltung nutzt dabei eine Reihe von Klassen: Dokumente, Computer, Textverarbeitungsprogramme, Drucker, Stifte, Stempel, Briefkästen und Briefmarkenautomaten. Das Klassensystem wird von verschiedenen Benutzern (Clients) verwendet: Einer nutzt lediglich den Computer um Texte zu schreiben, andere benötigen nur den Stift und wieder andere sind nur mit dem Frankieren und Versenden von Briefen beschäftigt.
Die meisten Benutzer des Systems wollen jedoch ein Schreiben aufsetzen, drucken und gleich verschicken. Dazu sind alle Systemklassen und eine Reihe von immer gleichen Befehlen notwendig:
Die notwendigen Schritte ausprogrammiert:
//Gegeben: Alle benötigten Klassen sind korrekt instanziiert, initialisiert und bekannt
String text = "Dieser Text soll verschickt werden";
//Computer muss angeschaltet werden.
computer.an();
//Zugriff auf das Textverarbeitungsprogramm über den Computer.
Textverarbeitungsprog textverarbeitungsprog = computer.getTextverarbeitungsprog();
//Das Textverarbeitungsprogramm muss geöffnet werden.
textverarbeitungsprog.oeffnen();
//Mit dem Textverarbeitungsprogramm muss das Dokument erstellt werden
Dokument dokument = textverarbeitungsprog.getDokument(text);
//Drucker muss angeschaltet werden
drucker.an();
//Drucker muss konfiguriert werden
drucker.konfigurieren();
//Papier muss in den Drucker gelegt werden
drucker.papierNachfuellen();
//Das Dokument muss gedruckt werden
computer.drucke(dokument);
//Der Drucker sollte ausgeschaltet werden
drucker.aus();
//Der Computer sollte ausgeschaltet werden
computer.aus();
//Das Dokument muss mit dem Stift unterschrieben werden
stift.unterschreiben(dokument);
//Das Dokument muss mit dem Stempel gestempelt werden
stempel.stempel(dokument);
//Das Dokument muss mit Hilfe des Briefmarkenautomaten frankiert werden
briefmarkenautomat.briefmarkeBezahlen(dokument, 2);
//Das Dokument muss schließlich in den Briefkasten geworfen werden.
briefkasten.briefEinwerfen(dokument);
Schauen wir uns diese Vorgehensweise genau an:
Wie wäre es, wenn wir eine Instanz zwischen System und Benutzern des System schalten? Diese Instanz stellt ein einheitliche und vereinfachte Schnittstelle (API) zum Schreiben, Drucken und Verschicken von Dokumenten bereit. Also, führen wir diese Instanz ein: die Sekretärin - unsere Fassade!
Die Sekretärin stellt eine vereinfachte Schnittstelle zur Nutzung des Systems bereit:
class Sekretaerin {
public void schreibenAufsetzen(String pString){
//Gegeben: Alle benötgiten Klassen sind korrekt instanziiert, initialisiert und bekannt
String text = "Dieser Text soll verschickt werden";
//Computer muss angeschaltet werden.
computer.an();
//Das Textverarbeitungsprogramm muss geöffnet werden.
Textverarbeitungsprog textverarbeitungsprog = computer.getTextverarbeitungsprog();
textverarbeitungsprog.oeffnen();
//Mit dem Textverarbeitungsprogramm muss das Dokument erstellt werden
Dokument dokument = textverarbeitungsprog.getDokument(text);
//Drucker muss angeschaltet werden
drucker.an();
//Drucker muss konfiguriert werden
drucker.konfigurieren();
//Papier muss in den Drucker gelegt werden
drucker.papierNachfuellen();
//Das Dokument muss gedruckt werden
computer.drucke(dokument);
//Der Drucker sollte ausgeschaltet werden
drucker.aus();
//Der Computer sollte ausgeschaltet werden
computer.aus();
//Das Dokument muss mit dem Stift unterschrieben werden
stift.unterschreiben(dokument);
//Das Dokument muss mit dem Stempel gestempelt werden
stempel.stempel(dokument);
//Das Dokument muss mit Hilfe des Briefmarkenautomaten frankiert werden
briefmarkenautomat.briefmarkeBezahlen(dokument, 2);
//Das Dokument muss schließlich in den Briefkasten geworfen werden.
briefkasten.briefEinwerfen(dokument);
}
//Instanzvariable der genutzten Objekte Computer, Drucker, Stift etc.
}
Der Client kann die Funktionalität des Systems fortan bequem über die Sekretärin nutzen:
Sekretaerin sekretaerin = new Sekretaerin();
sekretaerin.schreibenAufsetzen("Dieser Text soll verschickt werden");
Vorteile:
Nach dieser Einführung wird im folgenden Abschnitt das Facade Design Pattern (die Sekretärin ist eine Facade) formalisiert, näher analysiert und diskutiert.
| Klasse | Facade Teilnehmer |
|---|---|
| Sekretärin | Facade |
| System (Dokument, Computer, Drucker, Textverarbeitungsprogramm, Stift, Stempel, Briefmarkenautomat, Briefkasten) | Subsystem |
Facade:
"Biete eine einheitliche Schnittstelle zu einer Menge von Schnittstellen eines Subsystems. Die Fassadenklasse definiert eine abstrakte Schnittstelle, welche die Verwendung des Subsystems vereinfacht."
([GoF], Seite 212)
Das Facade Design Pattern definiert eine vereinfache Schnittstelle zur Benutzung eines Systems oder einer Menge von Objekten.
Gegeben sei ein komplexes Subsystem mit vielen Klassen und Abhängigkeiten zwischen ihnen. Clients die dieses Subsystem oder Teile davon nutzen möchten, müssen sich mit den verschiedenen Schnittstellen der enthaltenen Klassen befassen und die Funktionsweise verstehen. Dabei bauen sie zwangläufig viele Abhängigkeiten zu verschiedenen Objekten auf und koppeln sich eng an die Klassen des Subsystems.
Die Facade (dt. Fassade) wird zwischen Clients und dem Subsystem geschaltet. Es "kapselt" dabei das Subsystem, beinhaltet die komplexe Logik zum Arbeiten mit dem Subsystem und bietet für den Client eine vereinfachte Schnittstelle (Methoden) nach außen an. Die Fassade delegiert die Clientaufrufe ans Subsystem. Dadurch kann der Client das System über die Facade nutzen, ohne die Klassen, ihre Beziehungen, und Abhängigkeiten zu kennen.
Betrachtet man das Facade Design Pattern als Mittel um ganze Systeme zu kapseln, so ist es auch möglich, diese Systeme selbst wiederum aus Teilsystemen aufzubauen, die über Fassaden angesprochen werden können.
Fassaden entkoppeln die Clients von den Subsystem, dahin gehend, dass Änderungen am Subsystem den Client nicht beeinflussen. Denkt man diesen Gedanken konsequent zu ende, so lässt sich die Entkopplung noch weiter steigern, in dem der Client nur noch eine abstrakte Schnittstelle der Fassade kennt und gegen diese arbeitet. Unterklassen dieser abstrakten Fassadenschnittstelle delegieren, dann die Aufrufe des Clients an ihr Subsystem. Jede Unterklasse kann dabei mit einer ganz anderen Subsystemimplementierung arbeiten oder das gleiche Subsystem anders verwenden. Der Client weiß nicht, welche Subsytemimplementierung er gerade verwendet.

Alternativ kann die Fassade auch mit den gewünschten Subsystemobjekten konfiguriert werden, damit der Client mit dem benötigten, angepassten Subsystem arbeitet.
Eine entscheidende Frage dreht sich um die Sichtbarkeit der Subsystemklassen für den Client.
Sollten die Subsystemklassen dem Client weiterhin (neben der vereinfachten Facadeschnittstelle) zur Verfügung stehen, so kann der Client diese Klassen jederzeit nutzen, sollte die durch die Fassade bereitgestellten Methoden einmal nicht ausreichen. Ein Beispiel hierfür sind Anwendungen erfahrener Entwickler, die über den normalen Gebrauch des Subsystems hinausgehen. Diese Möglichkeit wird dabei offengehalten.
Häufig ist eine direkte Verwendung des Subsystems jedoch nicht gewünscht. Client sollen sich eben nicht hart an Subsystemobjekte koppeln, da ihr Code dann bei Änderungen bricht. Er soll allein die wohldefinierte und konsistente Fassadenschnittstelle nutzen. Dann muss sichergestellt werden, dass der Client nur Zugriff auf die Fassade hat. In Java kann dies mit Packages und default-Sichtbarkeit realisiert werden.
Das Facade Design Pattern kann angewandt werden, wenn...
[GoF] (Seite 212f) beschreibt das System eines Compilers, der aus vielen Klassen mit Verantwortlichkeiten besteht (Scanner, Parser, CodeGenerator, BytecodeStream, Token, Symbol etc.). Zu diesem System wird eine Fassade "Compiler" mit der Methode compile() definiert. Diese einfache Methode kapselt die notwendigen Schritte und das Zusammenspiel zwischen Objekten der Systemklassen, um einen Text zu compilieren. Der Client nutzt das Compilersystem über diese Schnittstelle der Compilerfassade. Fortgeschrittene Client können trotzdem weiterhin ausgewählte Objekte des Systems nutzen.
Änderungen im Subsystem pflanzen sich nicht mehr unkontrolliert durch die gesamte Applikation fort, sondern höchstens bis zur Implementierung der Facade. Die Facadeschnittstelle bleibt konstant. Die durch das Facade Design Pattern gewonnene Änderungsstabilität und den gesenkten Änderungsaufwand sei in folgenden Abbildungen illustriert.


Die Swing-Convenience-Klasse JOptionPane ist eine Fassade für Dialogfenster. Mit ihren statischen Methoden (showMessageDialog(), showInputDialog() etc.) stellt sie dem Client eine einfache Schnittstelle zur Erstellung von Dialogfenstern zur Verfügung. Der Client muss dabei keine Kenntnis von den verwendeten Swingkomponenten (JDialog, JRootPane, Frame), Layoutmanagern (BorderLayout), Listener (Windowlistener, Actionlistener) und den Utilityklassen (SunToolkit, SwingUtilities, UIManager, Math) haben.
Kommentare
Es sind keine Kommentare vorhanden