mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-10-14 00:16:48 +00:00
* docs: reformulate text, add links to further languages and paragraph about the book in central README.md (#2275) * docs: shorten text for link to payhip (#2275) * docs: reformulate german translation for Abstract Document (#2275) * Create folder for Abstract Factory * Create README.md for Abstract Document * Translate README.md for Abstract Document to German * correct typo * docs: add class diagrams for all patterns (#2275) * docs: add missing words in abstract-factory.README.md (#2275) * docs: Create German README.md for Active Object #2275 first text part * docs: finish German translation of README.md for Active Object * docs: translate actor-model into German #2295 * docs: add German translation for Acyclic Visitor #2295 * correct typo * docs: Translate Singleton into German #2295 * docs: Translate Prototype into German #2295 * Delete localization/de/Abstract Factory * insert line break * correct typos in actor-model * realignment of java code block * docs: translate Adapter Pattern into German #2295 * Update README.md change 'lizenz' to 'Lizenz' in badge * Update README.md translate 'benefits' and 'trade-offs' * remove additional bullet point after line break * correct indentation * docs: translate Dependency Injection into German #2295 * docs: translate Bridge into German #2295 * correct typos * docs: Translate Builder into German * delete english text * little changes in formulation * Update README.md change link to image * docs: remove spanish files (#2275) * docs: remove non-translated patterns (#2275) * Create README.md docs: Translate Step Builder into German #2275 * Create README.md docs: Translate Fluent Interface into German #2275 * eager is eifrig, not gierig * Translate Chain of Responsibility into German #2275
222 lines
7.5 KiB
Markdown
222 lines
7.5 KiB
Markdown
---
|
|
shortTitle: Chain of Responsibility
|
|
category: Behavioral
|
|
language: de
|
|
tag:
|
|
- Decoupling
|
|
- Event-driven
|
|
- Gang of Four
|
|
- Messaging
|
|
---
|
|
|
|
## Alternativbezeichnungen
|
|
|
|
* Chain of Command
|
|
* Chain of Objects
|
|
* Responsibility Chain
|
|
* deutsch: Zuständigkeitskette
|
|
|
|
## Zweck
|
|
|
|
Chain of Responsibility ist ein Verhaltensmuster,
|
|
das den Sender einer Anfrage von deren Empfängern entkoppelt, indem mehrere Objekte die
|
|
Gelegenheit zum Bearbeiten der Anfrage erhalten. Die empfangenden Objekte sind miteinander
|
|
verkettet und die Anfrage wird so lange entlang der Kette weitergereicht, bis ein Objekt
|
|
sie bearbeitet.
|
|
|
|
## Detaillierte Erklärung
|
|
|
|
Vergleichsbeispiel
|
|
|
|
> Die Chain of Responsibility gleicht der Arbeit in einem Call-Center für technischen
|
|
Kundendienst. Jedes Support-Level entspricht einem Handler in der Kette.
|
|
Wenn ein Kunde wegen eines Problems anruft, landet der Anruf bei einem Mitarbeiter des ersten
|
|
Levels. Einfache Probleme kann dieser direkt lösen. Wenn der Fall schwieriger ist, leitet
|
|
er den Anruf an einen Second-Level-Kollegen weiter. Dieser Prozess läuft über verschiedene
|
|
Stufen so lange weiter, bis ein Fachmann gefunden wurde, der das Problem löst.
|
|
Indem der Anruf entlang der Kette bis zur passenden Stelle weitergereicht wird,
|
|
erreicht man eine Entkopplung zwischen der Anfrage (Anruf) und ihrem Empfänger (jeweiliger
|
|
Mitarbeiter).
|
|
|
|
In einfachen Worten
|
|
|
|
> Das Pattern hilft beim Bau einer Kette von Objekten. Eine Anfrage kommt auf einer Seite herein
|
|
und wird von einem Objekt zum nächsten weitergereicht, bis der passende Handler für sie gefunden ist.
|
|
|
|
Wikipedia sagt
|
|
|
|
> Das Design-Pattern Chain of Responsibility besteht aus einer Quelle für Befehlsobjekt
|
|
und einer Reihe von Bearbeiterobjekten. Jedes Bearbeiterobjekt enthält eine Entscheidungslogik, welche
|
|
Art von Befehlsobjekten es selbst bearbeiten kann. Die übrigen leitet es an das nächste
|
|
Objekt in der Kette weiter.
|
|
|
|
Ablaufdiagramm
|
|
|
|

|
|
|
|
## Programmbeispiel
|
|
|
|
In diesem Java-Beispiel gibt der König der Orcs lautstarke Befehle an seine Armee, die von
|
|
einer Kette Untergebener ausgeführt werden. Am nächsten zum König steht sein General,
|
|
dann ein Offizier und schließlich ein einfacher Soldat.
|
|
|
|
Zuerst definieren wir für die Befehle die Klasse `Request`.
|
|
|
|
```java
|
|
public class Request {
|
|
|
|
private final RequestType requestType;
|
|
private final String requestDescription;
|
|
private boolean handled;
|
|
|
|
public Request(final RequestType requestType, final String requestDescription) {
|
|
this.requestType = Objects.requireNonNull(requestType);
|
|
this.requestDescription = Objects.requireNonNull(requestDescription);
|
|
}
|
|
|
|
public void markHandled() {
|
|
this.handled = true;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return getRequestDescription();
|
|
}
|
|
}
|
|
|
|
public enum RequestType {
|
|
DEFEND_CASTLE, TORTURE_PRISONER, COLLECT_TAX
|
|
}
|
|
```
|
|
|
|
Hier sehen wir die Hierarchie der `RequestHandler`.
|
|
|
|
```java
|
|
public interface RequestHandler {
|
|
|
|
boolean canHandleRequest(Request req);
|
|
|
|
int getPriority();
|
|
|
|
void handle(Request req);
|
|
|
|
String name();
|
|
}
|
|
|
|
public class OrcCommander implements RequestHandler {
|
|
@Override
|
|
public boolean canHandleRequest(Request req) {
|
|
return req.getRequestType() == RequestType.DEFEND_CASTLE;
|
|
}
|
|
|
|
@Override
|
|
public int getPriority() {
|
|
return 2;
|
|
}
|
|
|
|
@Override
|
|
public void handle(Request req) {
|
|
req.markHandled();
|
|
LOGGER.info("{} handling request \"{}\"", name(), req);
|
|
}
|
|
|
|
@Override
|
|
public String name() {
|
|
return "Orc commander";
|
|
}
|
|
}
|
|
|
|
// OrcOfficer und OrcSoldier sind ähnlich definiert
|
|
|
|
```
|
|
|
|
Der `OrcKing` gibt den Befehl und baut die Kette (geordnet nach Priorität) auf:
|
|
|
|
```java
|
|
public class OrcKing {
|
|
|
|
private List<RequestHandler> handlers;
|
|
|
|
public OrcKing() {
|
|
buildChain();
|
|
}
|
|
|
|
private void buildChain() {
|
|
handlers = Arrays.asList(new OrcCommander(), new OrcOfficer(), new OrcSoldier());
|
|
}
|
|
|
|
public void makeRequest(Request req) {
|
|
handlers
|
|
.stream()
|
|
.sorted(Comparator.comparing(RequestHandler::getPriority))
|
|
.filter(handler -> handler.canHandleRequest(req))
|
|
.findFirst()
|
|
.ifPresent(handler -> handler.handle(req));
|
|
}
|
|
}
|
|
```
|
|
|
|
Hier erhält die Kette verschiedene Befehle:
|
|
|
|
```java
|
|
public static void main(String[] args) {
|
|
|
|
var king = new OrcKing();
|
|
king.makeRequest(new Request(RequestType.DEFEND_CASTLE, "defend castle"));
|
|
king.makeRequest(new Request(RequestType.TORTURE_PRISONER, "torture prisoner"));
|
|
king.makeRequest(new Request(RequestType.COLLECT_TAX, "collect tax"));
|
|
}
|
|
```
|
|
|
|
Ausgabe:
|
|
|
|
```
|
|
Orc commander handling request "defend castle"
|
|
Orc officer handling request "torture prisoner"
|
|
Orc soldier handling request "collect tax"
|
|
```
|
|
|
|
## Verwendung
|
|
|
|
* Wenn mehrere Objekte eine Anfrage bearbeiten können und der zuständige Verarbeiter nicht
|
|
vorab bekannt ist. Der Verarbeiter sollte automatisch ermittelt werden.
|
|
* Wenn eine Anfrage an eines von mehreren Objekten gesendet wird, ohne den Empfänger explizit festzulegen.
|
|
* Bei dynamischer Zusammenstellung der Menge möglicher Bearbeiter.
|
|
|
|
## Reale Anwendungen in Java
|
|
|
|
* Event-Bubbling in GUI-Frameworks, wo ein Event in verschiedenen Stufen der Komponentenhierachie bearbeitet werden kann.
|
|
* Middleware-Frameworks, bei denen Anfragen eine Kette möglicher Verarbeiter durchlaufen.
|
|
* Logging-Frameworks, bei denen Nachrichten eine Reihe von Loggern durchlaufen, von denen sie verschieden behandelt werden können.
|
|
* [java.util.logging.Logger#log()](http://docs.oracle.com/javase/8/docs/api/java/util/logging/Logger.html#log%28java.util.logging.Level,%20java.lang.String%29)
|
|
* [Apache Commons Chain](https://commons.apache.org/proper/commons-chain/index.html)
|
|
* [javax.servlet.Filter#doFilter()](http://docs.oracle.com/javaee/7/api/javax/servlet/Filter.html#doFilter-javax.servlet.ServletRequest-javax.servlet.ServletResponse-javax.servlet.FilterChain-)
|
|
|
|
## Vor- und Nachteile
|
|
|
|
Vorteile:
|
|
|
|
* Weniger Kopplung. Der Sender einer Anfrage muss nicht wissen, von wem diese bearbeitet wird.
|
|
* Flexibilität bei der Zuweisung von Verantwortlichkeiten durch Umbildung der Kette.
|
|
* Für den Fall, dass kein Kettenglied die Anfrage bearbeiten kann, kann ein Default-Verarbeiter festgelegt werden.
|
|
|
|
Nachteile:
|
|
|
|
* Bei langen und komplexen Ketten kann der Ablauf schwer zu durchschauen und zu debuggen sein.
|
|
* Eine Anfrage kann unbearbeitet bleiben, wenn ein passender Bearbeiter fehlt.
|
|
* Der (möglicherweise auch vergebliche) Durchlauf durch mehrere Verarbeiter kann die Peformance beeinträchtigen.
|
|
|
|
## Verwandte Patterns
|
|
|
|
* [Command](https://java-design-patterns.com/patterns/command/): Kann verwendet werden zur Kapselung der Anfrage in ein Objekt, das durch die Kette läuft.
|
|
* [Composite](https://java-design-patterns.com/patterns/composite/): Wird oft gemeinsam mit Chain of Responsibility verwendet.
|
|
* [Decorator](https://java-design-patterns.com/patterns/decorator/): Decorators können ähnlich wie Verantwortlichkeiten verkettet werden.
|
|
|
|
## Quellen
|
|
|
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI)
|
|
* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/49NGldq)
|
|
* [Pattern-Oriented Software Architecture, Volume 1: A System of Patterns](https://amzn.to/3PAJUg5)
|
|
* [Refactoring to Patterns](https://amzn.to/3VOO4F5)
|
|
* [Pattern languages of program design 3](https://amzn.to/4a4NxTH)
|