Zuständigkeitskette
Die Zuständigkeitskette (englisch chain of responsibility) ist ein in der Softwareentwicklung eingesetztes Entwurfsmuster. Es gehört zur Kategorie der Verhaltensmuster (englisch behavioral design patterns) und wird für Algorithmen verwendet. Dabei dient es der Entkopplung des Auslösers einer Anfrage mit seinem Empfänger.[1] Das Muster ist eines der sogenannten GoF-Muster (siehe Viererbande, Gang of Four).
Verwendung
[Bearbeiten | Quelltext bearbeiten ]Mehrere Objekte werden hintereinander geschaltet (miteinander verkettet), um gemeinsam eine eingehende Anfrage bearbeiten zu können. Diese Anfrage wird an der Kette entlang geleitet, bis eines der Objekte die Anfrage beantworten kann. Der Klient, von dem die Anfrage ausgeht, hat dabei keine Kenntnis darüber, von welchem Objekt die Anfrage beantwortet werden wird.
UML-Diagramm
[Bearbeiten | Quelltext bearbeiten ]Akteure
[Bearbeiten | Quelltext bearbeiten ]Bei einer Zuständigkeitskette spielen drei Akteure eine Rolle:
- Bearbeiter, der ein Interface für die Anfragen definiert
- konkreter Bearbeiter, der alle Anfragen bearbeitet, für die er selbst zuständig ist und alle anderen Anfragen an das nächste Kettenglied (den nächsten Bearbeiter) weiterleitet
- Klient, der die Anfrage an irgendeinem konkreten Bearbeiter initiiert.
Vor- und Nachteile
[Bearbeiten | Quelltext bearbeiten ]Ein Vorteil ist, dass der Klient den tatsächlich zuständigen Bearbeiter nicht kennen muss. Selbst die Kettenglieder müssen nur ihren direkten Nachfolger und nicht den Gesamt-Aufbau der Kette kennen. Dies führt zu einer geringeren Kopplung. Außerdem kann die Zuständigkeit von Objekten für bestimmte Anfragen verändert werden, ohne dass potenzielle Klienten davon in Kenntnis gesetzt werden müssen.
Es gibt auf der anderen Seite keine Garantie, dass die Anfrage tatsächlich bearbeitet wird. Wenn das letzte Glied der Kette eine Anfrage erhält, für die es ebenfalls nicht zuständig ist, wird die Anfrage nach obigem Muster verworfen. Dies muss durch eine entsprechende Fallbehandlung abgefangen werden.
Es muss sichergestellt werden, dass jeder Bearbeiter in der Kette nur einmal vorkommt, sonst entstehen Kreise und das Programm bleibt in einer Endlosschleife hängen.
Beispiel
[Bearbeiten | Quelltext bearbeiten ]Diese C++11 Implementierung basiert auf der vor C++98 Implementierung im Buch Entwurfsmuster.
#include<iostream> #include<memory> typedefintThema; constexprThemaKEIN_HILFE_THEMA=-1; // definiert eine Schnittstelle zur Bearbeitung von Anfragen. classHilfeBearbeiter{// Bearbeiter public: HilfeBearbeiter(HilfeBearbeiter*h=nullptr,Themat=KEIN_HILFE_THEMA) :nachfolger(h),thema(t){} virtualboolhatHilfe(){ returnthema!=KEIN_HILFE_THEMA; } virtualvoidsetBearbeiter(HilfeBearbeiter*,Thema){} virtualvoidbearbeiteHilfe(){ std::cout<<"HilfeBearbeiter::bearbeiteHilfe\n"; // (optional) implementiert eine Verbindung zum Nachfolgeobjekt. if(nachfolger!=nullptr){ nachfolger->bearbeiteHilfe(); } } virtual~HilfeBearbeiter()=default; HilfeBearbeiter(constHilfeBearbeiter&)=delete;// Dreierregel HilfeBearbeiter&operator=(constHilfeBearbeiter&)=delete; private: HilfeBearbeiter*nachfolger; Themathema; }; classWidget:publicHilfeBearbeiter{ public: Widget(constWidget&)=delete;// Dreierregel Widget&operator=(constWidget&)=delete; protected: Widget(Widget*w,Themat=KEIN_HILFE_THEMA) :HilfeBearbeiter(w,t),elternObjekt(nullptr){ elternObjekt=w; } private: Widget*elternObjekt; }; classButton:publicWidget{// KonkreterBearbeiter public: Button(std::shared_ptr<Widget>h,Themat=KEIN_HILFE_THEMA):Widget(h.get(),t){} virtualvoidbearbeiteHilfe(){ // wenn der KonkreteBearbeiter die Anfrage bearbeiten kann, tut er es auch; andernfalls leitet er die Anfrage an das Nachfolgeobjekt weiter. std::cout<<"Button::bearbeiteHilfe\n"; if(hatHilfe()){ // arbeitet genau die Anfrage ab, für die er zuständig ist. }else{ // kann auf seinen Nachfolger zugreifen. HilfeBearbeiter::bearbeiteHilfe(); } } }; classDialog:publicWidget{// KonkreterBearbeiter public: Dialog(std::shared_ptr<HilfeBearbeiter>h,Themat=KEIN_HILFE_THEMA):Widget(nullptr){ setBearbeiter(h.get(),t); } virtualvoidbearbeiteHilfe(){ std::cout<<"Dialog::bearbeiteHilfe\n"; if(hatHilfe()){ // biete Hilfsinformationen für den Dialog an }else{ HilfeBearbeiter::bearbeiteHilfe(); } } }; classAnwendung:publicHilfeBearbeiter{ public: Anwendung(Themat):HilfeBearbeiter(nullptr,t){} virtualvoidbearbeiteHilfe(){ std::cout<<"Anwendung::bearbeiteHilfe\n"; // zeige eine Liste von Hilfsthemen an } }; intmain(){ constexprThemaDRUCKE_THEMA=1; constexprThemaPAPIER_ORIENTIERUNG_THEMA=2; constexprThemaANWENDUNG_THEMA=3; // Die Smart pointers verhindern Memory leaks. std::shared_ptr<Anwendung>application=std::make_shared<Anwendung>(ANWENDUNG_THEMA); std::shared_ptr<Dialog>dialog=std::make_shared<Dialog>(application,DRUCKE_THEMA); std::shared_ptr<Button>button=std::make_shared<Button>(dialog,PAPIER_ORIENTIERUNG_THEMA); button->bearbeiteHilfe(); }
Die Programmausgabe ist:
Button::bearbeiteHilfe
Verwandte Entwurfsmuster
[Bearbeiten | Quelltext bearbeiten ]Ein verwandtes Entwurfsmuster ist der Decorator: Vor oder nachdem eine Anfrage weitergeleitet wird, können zusätzliche Operationen erfolgen, wie zum Beispiel Gültigkeitsprüfungen. Außerdem ähnlich ist das Kompositum. Dabei wird die Anfrage so lange vom Child zum Parent weitergereicht, bis sie beantwortet wird oder kein weiteres Objekt folgt. Eine weitere Möglichkeit ergibt sich durch einen Iterator über Objekte mit Schablonenmethoden.
Einzelnachweise
[Bearbeiten | Quelltext bearbeiten ]- ↑ Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides: Entwurfsmuster. 5. Auflage. Addison-Wesley, 1996, ISBN 3-8273-1862-9, S. 410.
Abstrakte Fabrik | Erbauer | Fabrikmethode | Prototyp | Singleton | Multiton | Objektpool
Adapter | Brücke | Decorator | Fassade | Fliegengewicht | Kompositum | Stellvertreter
Beobachter | Besucher | Interpreter | Iterator | Kommando | Memento | Schablonenmethode | Strategie | Vermittler | Zustand | Zuständigkeitskette | Interceptor | Nullobjekt | Protokollstapel
relationale Abbildung
Datentransferobjekt | Table Data Gateway | Row Data Gateway | Active Record | Unit of Work | Identity Map | Lazy Loading | Identity Field | Dependent Mapping | Embedded Value | Serialized LOB | Inheritance Mapper | Metadata Mapping | Query Object | Command-Query-Responsibility-Segregation
übermittlungsmuster
File Transfer | Shared Database | Remote Procedure Invocation | Messaging
Message | Command Message | Document Message | Event Message | Request-Reply | Return Address | Correlation Identifier | Message Sequence | Message Expiration | Format Indicator
Message Endpoint | Messaging Gateway | Messaging Mapper | Transactional Client | Polling Consumer | Event-driven Consumer | Competing Consumers | Message Dispatcher | Selective Consumer | Durable Subscriber | Idempotent Receiver | Service Activator
Message Channel | Point-to-Point Channel | Publisher-Subscriber Channel | Datatype Channel | Invalid Message Channel | Dead Letter Channel | Guaranteed Delivery | Channel Adapter | Messaging Bridge | Message Bus
Pipes-and-Filters | Message Router | Content-based Router | Message Filter | Dynamic Router | Recipient List | Splitter | Aggregator | Resequencer | Composed Message Processor | Scatter-Gather | Routing Slip | Process Manager | Message Broker
Message Translator | Envelope Wrapper | Content Enricher | Content Filter | Claim Check | Normalizer | Canonical Data Model
Control Bus | Detour | Wire Tap | Message History | Message Store | Smart Proxy | Test Message | Channel Purger
Application Controller | Business Delegate | Data Access Object | Dependency Injection | Extension Interface | Fluent Interface | Inversion of Control (IoC) | Lock | Model View Controller (MVC) | Model View Presenter (MVP) | Model View Update (MVU) | Model View ViewModel (MVVM) | Page Controller | Registry | Remote Facade | Repository | Service Locator | Session State | Table Module | Template View | Threadpool | Transaction Script | Transform View | Two-Step View | Value Object