Auf der Suche nach ge­eig­ne­ten Stra­te­gien zur Ver­ein­fa­chung komplexer Software trifft man un­wei­ger­lich auf das Facade Design Pattern (dt. Fassaden-Ent­wurfs­mus­ter) oder kurz einfach nur Facade Pattern. Neben anderen Ver­tre­tern wie dem Decorator Pattern oder dem Composite Pattern zählt es zur Kategorie der Struk­tur­mus­ter der so­ge­nann­ten GoF-Ent­wurfs­mus­ter (die Abkürzung „GoF“ steht für „Gang of Four“), die das Software-Design seit ihrer Ver­öf­fent­li­chung im Jahr 1994 ent­schei­dend prägen.

Was genau das Facade Pattern ist und in welcher Hinsicht es Ent­wick­lern bei der Ent­zer­rung von Sub­sys­te­men wei­ter­hilft, erfahren Sie in den nach­fol­gen­den Ab­schnit­ten.

Was ist das Facade Pattern (Facade-Ent­wurfs­mus­ter)?

Das Facade Design Pattern ist eines der 23 so­ge­nann­ten GoF-Design-Patterns, die 1994 als Leitfäden für die Software-Ent­wick­lung von den vier Autoren Erich Gamma, Ralph Johnson, Richard Helm und John Vlissides in „Design Patterns: Elements of Reusable Object-Oriented Software“ ver­öf­fent­lich wurden. Dem all­ge­mei­nen Grundsatz dieser Patterns folgend, die Kreation flexibler, wie­der­ver­wend­ba­rer Software zu ver­ein­fa­chen, definiert das Facade Pattern eine Mus­ter­lö­sung zur einfachen Zu­sam­men­füh­rung ver­schie­de­ner Schnitt­stel­len in komplexen Systemen. Eine uni­ver­sel­le Fassaden-Klasse, die gleich­zei­tig als Schnitt­stel­le fungiert, delegiert dabei wichtige Funk­tio­na­li­tä­ten der Software an die je­wei­li­gen Sub­sys­te­me, um den Umgang mit den ver­schie­de­nen Teil­kom­po­nen­ten eines Programms so einfach wie möglich zu gestalten.

Welche Probleme löst der Facade-Pattern-Ansatz?

Clients, die auf ein komplexes Subsystem zugreifen, beziehen sich direkt auf eine Vielzahl von Objekten mit ganz ver­schie­de­nen Schnitt­stel­len oder sind von diesen Objekten abhängig. Das macht die Im­ple­men­tie­rung, Anpassung sowie das Testen und die Wie­der­ver­wen­dung der Clients aus Ent­wick­ler­sicht besonders schwierig – und bringt das Facade Design Pattern ins Spiel:

Das Facade-Ent­wurfs­mus­ter sieht die De­fi­ni­ti­on eines zentralen Facade-Objekts (auch als „Fassade“ be­zeich­net) vor, das:

  • ein uni­ver­sel­les Interface für die ver­schie­de­nen Schnitt­stel­len des Sub­sys­tems bzw. der Sub­sys­te­me im­ple­men­tiert.
  • und (bei Bedarf) zu­sätz­li­che Funk­tio­nen vor oder nach der Wei­ter­lei­tung einer Client-Anfrage ausführen kann.

Als Ver­mitt­ler sorgt das Facade-Objekt dafür, dass der Zugriff bzw. die Kom­mu­ni­ka­ti­on mit den einzelnen Kom­po­nen­ten eines Sub­sys­tems ver­ein­facht und damit auch die direkte Ab­hän­gig­keit von diesen Kom­po­nen­ten minimiert wird. Es delegiert die Cli­ent­auf­ru­fe, sodass Clients weder die Klassen noch ihre Be­zie­hun­gen und Ab­hän­gig­kei­ten kennen müssen.

Facade Pattern: UML-Klas­sen­dia­gramm des Fassaden-Musters

Die Fassade bzw. die Facade-Klasse ist die ent­schei­den­de Struk­tu­rie­rungs­ein­heit des Facade Patterns. Ihre Im­ple­men­tie­rung und Aus­ar­bei­tung ist also die grund­le­gen­de Aufgabe für Ent­wick­ler, die ihre komplexe Software mithilfe dieses prak­ti­schen Ent­wurfs­mus­ters ver­ein­fa­chen möchten. Einmal umgesetzt, kon­zen­trie­ren die be­trof­fe­nen Client-Objekte ihre gesamte Kom­mu­ni­ka­ti­on auf die Facade-Klasse, die damit in diesem neuen System zur einzigen Instanz wird, von der die Clients direkt abhängig sind.

Das nach­fol­gen­de UML-Diagramm stellt das Zu­sam­men­spiel von Clients, Fassade und Subsystem-Klassen nach dem Facade-Pattern zur Ver­an­schau­li­chung grafisch dar.

Facade Pattern: Vorteile und Nachteile

Die Stärken des Facade Design Patterns liegen auf der Hand: Die Fassade „versteckt“ zu­grun­de­lie­gen­de Sub­sys­te­me einer Software und senkt dadurch die Kom­ple­xi­tät dieser Systeme. Zu­sätz­lich fördert dieser Ansatz das Prinzip der losen Kopplung. Durch den geringen Grad der Ab­hän­gig­keit der einzelnen Kom­po­nen­ten un­ter­ein­an­der sind Än­de­run­gen (Mo­di­fi­zie­run­gen, Wartungen) jederzeit ohne größere Umstände möglich, da die Än­de­run­gen sich zum Großteil nur lokal auswirken. Diese lose Kopplung sorgt außerdem dafür, dass ein Subsystem einfacher zu erweitern ist.

Hinweis

Sollten Clients auf einen direkten Zugriff auf bestimmte Klassen des Sub­sys­tems an­ge­wie­sen sein, kann dieser auch im Facade-Pattern-Modell gewährt werden: In diesem Fall ist lediglich die Sicht­bar­keit des Sub­sys­tems so zu pro­gram­mie­ren, dass ein Client die Fassade bei Bedarf übergehen kann.

Der Einsatz des Facade-Ent­wurfs­mus­ters kann jedoch auch ent­schei­den­de Nachteile mit sich bringen: Die Im­ple­men­tie­rung einer Fassade ist – durch ihre zentrale Rolle – eine sehr mühsame und kom­pli­zier­te Aufgabe, ins­be­son­de­re, wenn sie in bereits be­stehen­den Code eingefügt werden soll. Generell bedeutet der Einbau eines Facade-In­ter­faces eine zu­sätz­li­che In­di­rek­ti­ons­stu­fe, die an zu­sätz­li­che Re­chen­zeit für Methoden- und Funk­ti­ons­auf­ru­fe, Spei­cher­zu­grif­fe etc. geknüpft ist. Schließ­lich birgt das Facade Pattern auch das Risiko, dass die Ab­hän­gig­keit der Software von der zentralen Ober-Schnitt­stel­le zu groß wird.

Vorteile Nachteile
Minimiert die Kom­ple­xi­tät von Sub­sys­te­men Im­ple­men­tie­rung aufwändig (ins­be­son­de­re bei bereits be­stehen­dem Code)
Fördert das Prinzip der losen Kopplung Ansatz ist an eine zu­sätz­li­che In­di­rek­ti­ons­stu­fe gekoppelt
Software wird flexibler und leichter er­wei­ter­bar Hoher Ab­hän­gig­keits­grad von der Facade-Schnitt­stel­le

Typische An­wen­dungs­fäl­le für das Facade Design Pattern

Die Ei­gen­schaf­ten des Facade-Ent­wurfs­mus­ters machen es gleich für mehrere Ein­satz­sze­na­ri­os in­ter­es­sant. Allen voran steht der Wunsch nach einer ein­heit­li­chen Schnitt­stel­le für den Zugriff auf komplexe Sub­sys­te­me oder eine beliebige Menge an Objekten. Hier ver­spricht eine Fassade eine deutliche Ver­ein­fa­chung, weshalb der Einsatz der Facade-Pattern-Strategie bei der Planung des Projekts eine über­ge­ord­ne­te Rolle spielen sollte.

Ein weiterer typischer An­wen­dungs­fall ist Software, bei der die Ab­hän­gig­keit zwischen Clients und zu­grun­de­lie­gen­den Sub­sys­te­men minimiert werden soll.

Zuletzt zahlt sich der Facade-Pattern-Ansatz aus, wenn Sie ein Software-Projekt planen, das in mehrere Schichten un­ter­teilt werden soll. Fassaden als Kom­mu­ni­ka­ti­ons­schnitt­stel­len zwischen den Schichten sorgen auch dabei für mehr Fle­xi­bi­li­tät bei der späteren Er­wei­te­rung und Anpassung der Kom­po­nen­ten.

Praxis-Beispiel für die Umsetzung des Facade Patterns

Das Facade Design Pattern ist als Ent­wurfs­mus­ter nicht an eine bestimmte Pro­gram­mier­spra­che gebunden. Unter anderem kommt die Strategie bei­spiels­wei­se in C++, C#, Ja­va­Script, Java, PHP und Python zum Einsatz. Im nach­fol­gen­den Facade-Pattern-Beispiel, bei dem wir uns an dem Facade-Pattern-Tutorial auf tu­to­ri­al­s­point ori­en­tiert haben, handelt es sich daher nur ex­em­pla­risch um einen Java-Code.

Im Beispiel soll ein uni­ver­sell geltendes Interface „Shape“ für Objekte definiert werden, die geo­me­tri­sche Formen re­prä­sen­tie­ren. Zudem werden konkrete Klassen generiert, die dieses Interface im­ple­men­tie­ren, sowie eine Facade-Klasse namens „Shape­Ma­ker“, die für das De­le­gie­ren der Client-Anfragen ver­ant­wort­lich ist.

Zunächst erstellen wir das Interface Shape.java mit folgendem Code:

public interface Shape {
	void draw();
}

Im zweiten Schritt werden mit Rectangle.java (Klasse für recht­ecki­ge Objekte), Square.java (Klasse für qua­dra­ti­sche Objekte) und Circle.java (Klasse für kreis­för­mi­ge Objekte) drei konkrete Klassen erzeugt, die das Interface im­ple­men­tie­ren.

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

Schließ­lich wird die Facade-Klasse ShapeMaker in den Code in­te­griert, die fortan von den Clients an­ge­spro­chen werden kann, um die ver­schie­de­nen Formen zu erzeugen:

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