Daniel Hundt - Erfahrung Technologien im Backend

zurück zur Technologie-Übersicht

Design-Pattern: Responsibility-Chain

Inhalt

Module die verkettet werden können
Jedes Modul hat seine EINE Aufgabe. Die einzelnen Module teilen sich die selbe Schnittstelle und sind somit frei kombinierbar.
Implementierung 1 und 2 nutzen ebenfalls die selbe Schnittstelle (ggf. mit anderem Ergebnis), Implementierung 3 jedoch nicht.

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

Beispielhafte Verkettung der Funktionseinheiten
Beispielhafte Verkettung der Funktionseinheiten
  • 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