Design-Pattern: Responsibility-Chain
Inhalt
Single Responsibility
Jedes Modul / jede Klasse hat genau einen Zweck.
Dadurch lassen sich mögliche Fehler einfacher lokalisieren und eine Umfangreiche Abdeckung mit Testfällen ist sinnvoll möglich. Außerdem können so einzelnen Module in ihrem Funktionsumfang (für diesen einen Zweck!) erweitert werden.
Modul-Kette
Jedes Modul implementiert das gleiche Interface.
Dadurch können die Module frei miteinander kombiniert werden. Über eine Factory können so z.B. bestimmte Kombinationen / Strategien erstellt bzw. konfiguriert werden.
Module
Hier sollen die einzelnen Funktions-Module kurz vorgestellt werden.
Zugriffskontrolle
Der Zugriff auf eine Funktion ist nur beim Erfüllen bestimmter Kriterien (z.B. korrektes Login) möglich.
Meist sind dazu weitere Attribute nötig, so dass das Interface erweitert werden muss.
Hier kann z.B. ein Nutzer-/Rollen-Konzept implementiert werden.
Cache
Bevor die Anfrage an die Implementierung (bzw. die nächste Schicht) weitergeleitet wird, wird geprüft, ob für diese Anfrage schon eine Antwort gespeichert wurde.
Ist dies der Fall, muss die Anfrage nicht weitergereicht werden, wodurch die Last reduziert und die Performance gesteigert werden kann.
Ist noch kein Cache-Eintrag vorhanden, wird die Implementierung befragt und das Ergebnis im Cache gespeichert.
Hier können z.B. verschiedene Orte (RAM, Festplatte) und Haltezeiten (nach der der Eintrag verworfen wird) implementiert werden.
Log
Anfrage und Ergebnis werden durch diese Schicht geloggt. Ob für Debugging-Zwecke oder zur späteren statistischen Auswertung.
Hier können z.B. mehrere Orte (Log-File, Email) und Log-Formate implementiert werden.
Umformung
Bevor eine Anfrage an die nächste Schicht weitergeleitet wird, wird sie umgestellt.
Hier kann z.B. die Anfrage normalisiert (trim) oder Informationen ergänzt werden.
Übersteuerung
Ähnlich der Umformung ist eine Übersteuerung der Anfrage aber auch des Ergebnisses (ähnlich Cache) möglich.
Hier kann z.B. eine manuelle Fehlerkorrektur für Sonderfälle implementiert werden.
Verteiler
Der Verteiler verteilt die Anfrage auf Grund eigener Kriterien auf mehrere Endpunkte.
Hier kann z.B. eine Last-Verteilung, eine Abfrage-Strategie oder Replizierung implementiert werden.
Linker
Der Linker ist ähnlich dem Verteiler. Er fragt mehrere Endpunkte ab und kombiniert das Ergebnis.
Hier kann z.B. ein Fallback-Szenario oder die Kombination aus mehreren Datenquellen implementiert werden.
Converter
Der Converter bzw. Adapter oder Wrapper stellt wie die anderen Module das gleiche Interface zur Verfügung,
wandelt die Anfrage aber so um, dass sie von einer Implementierung mit anderem Interface bearbeitet werden kann.
Er dient quasi als Zwischenstück zwischen 2 nicht passenden Teilen.
Hier wird z.B. sichergestellt, dass auch Fremd-APIs die geforderte Schnittstelle erfüllen.
Beispiel
- Log 1: Die initiale Anfrage und die Antwort darauf werden geloggt
- Umformung: Die Anfrage wird normalisiert (doppelte Leerzeichen entfernen etc.)
- Log 2: Die Anfrage nach der Umformung wird geloggt
-
Cache 1: Es wird geprüft, ob bereits eine gültige Antwort für die Anfrage existiert
- Log 3: Es wird festgehalten, wie oft der Cache genutzt wurde
-
Linker: Im Normalfall wird der obere Weg (Verteiler) bemüht. Ist die Antwort nach einer bestimmten Zeit nicht da, wird der untere Weg (Cache 2) bemüht
-
Verteiler 1: Die Anfrage wird je nach Typ an Implementierung 2 oder 3 weitergeleitet
- Übersteuerung: Implementierung 2 enthält einige bekannte Fehler, die hier abgefangen werden
- Converter: Implementierung 3 hat ein anderes Interface wesshalb der Converter zum Einsatz kommt
-
Cache 2: Prüft, ob bereits gültige Ergebnisse aus Implementierung 1 vorliegen
-
Verteiler 2: Je nach Lastsituation und Erreichbarkeit wird entweder Server A oder B befragt
-
Verteiler 1: Die Anfrage wird je nach Typ an Implementierung 2 oder 3 weitergeleitet