Chain of Responsibility



Ähnliche Dokumente
Daniel Warneke Ein Vortrag im Rahmen des Proseminars Software Pioneers

Fassade. Objektbasiertes Strukturmuster. C. Restorff & M. Rohlfing

Drei-Schichten-Architektur. Informatik B - Objektorientierte Programmierung in Java. Vorlesung 16: 3-Schichten-Architektur 1 Fachkonzept - GUI

Software-Entwurfsmuster

Klassenentwurf. Wie schreiben wir Klassen, die leicht zu verstehen, wartbar und wiederverwendbar sind? Objektorientierte Programmierung mit Java

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {...

Vererbung & Schnittstellen in C#

Objektorientierte Programmierung

Software Engineering Klassendiagramme Assoziationen

SEP 114. Design by Contract

Vermittler (Mediator) Sabine Müller - Sven Richter - Jens Wagenbreth 03IN2-P-D

Urlaubsregel in David

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Fachdidaktik der Informatik Jörg Depner, Kathrin Gaißer

Software Engineering Interaktionsdiagramme

Objektorientierte Programmierung. Kapitel 12: Interfaces

Objektorientierte Programmierung für Anfänger am Beispiel PHP

Arbeiten mit UMLed und Delphi

Programmieren in Java

Es sollte die MS-DOS Eingabeaufforderung starten. Geben Sie nun den Befehl javac ein.

Zwischenablage (Bilder, Texte,...)

C# im Vergleich zu Java

Folge 19 - Bäume Binärbäume - Allgemeines. Grundlagen: Ulrich Helmich: Informatik 2 mit BlueJ - Ein Kurs für die Stufe 12

Grundlagen der Theoretischen Informatik, SoSe 2008

Java Kurs für Anfänger Einheit 5 Methoden

Outlook. sysplus.ch outlook - mail-grundlagen Seite 1/8. Mail-Grundlagen. Posteingang

Novell Client. Anleitung. zur Verfügung gestellt durch: ZID Dezentrale Systeme. Februar ZID Dezentrale Systeme

Professionelle Seminare im Bereich MS-Office

Übung 6: Feinentwurf. Prof. Dr. Dr. h.c. Manfred Broy Dr. Herbert Ehler, Martin Feilkas 6. Juli 2006 Bernd Spanfelner, Sebastian Winter

Objektorientierte Programmierung OOP

Anleitung zur Verwendung der VVW-Word-Vorlagen

Fehler und Probleme bei Auswahl und Installation eines Dokumentenmanagement Systems

Prinzipien Objektorientierter Programmierung

Java: Vererbung. Teil 3: super()

1 Mathematische Grundlagen

Übungen zur Softwaretechnik

Microsoft Access 2013 Navigationsformular (Musterlösung)

Konfiguration VLAN's. Konfiguration VLAN's IACBOX.COM. Version Deutsch

Analyse und Modellierung von Informationssystemen

Sich einen eigenen Blog anzulegen, ist gar nicht so schwer. Es gibt verschiedene Anbieter. ist einer davon.

Erstellen von x-y-diagrammen in OpenOffice.calc

Das Leitbild vom Verein WIR

Analyse und Modellierung von Informationssystemen

Anleitung über den Umgang mit Schildern

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

AZK 1- Freistil. Der Dialog "Arbeitszeitkonten" Grundsätzliches zum Dialog "Arbeitszeitkonten"

Anwendungsbeispiele. Neuerungen in den s. Webling ist ein Produkt der Firma:

NetStream Helpdesk-Online. Verwalten und erstellen Sie Ihre eigenen Tickets

Objektorientierte Programmierung

FORUM HANDREICHUNG (STAND: AUGUST 2013)

Was meinen die Leute eigentlich mit: Grexit?

Fachgebiet Informationssysteme Prof. Dr.-Ing. N. Fuhr. Programmierung Prof. Dr.-Ing. Nobert Fuhr. Übungsblatt Nr. 6

mysql - Clients MySQL - Abfragen eine serverbasierenden Datenbank

Leichte-Sprache-Bilder

Kapitel 4 Die Datenbank Kuchenbestellung Seite 1

WPF Steuerelemente Listbox, ComboBox, ListView,

Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung: Lösungsvorschlag

Bedienung von BlueJ. Klassenanzeige

Wintersemester Maschinenbau und Kunststofftechnik. Informatik. Tobias Wolf Seite 1 von 22

.NET Code schützen. Projekt.NET. Version 1.0

Drägerware.ZMS/FLORIX Hessen

Objektorientiertes Software-Engineering

PowerPoint 2010 Mit Folienmastern arbeiten

Proseminar: Website-Managment-System. NetObjects Fusion. von Christoph Feller

Lieber SPAMRobin -Kunde!

Einrichten eines Postfachs mit Outlook Express / Outlook bis Version 2000

Bilder zum Upload verkleinern

! " # $ " % & Nicki Wruck worldwidewruck

Berechtigungen im Kalender Anleitung für die Rechtevergabe im Outlook Kalender FHNW, Services, ICT

Anleitung Postfachsystem Inhalt

In 15 einfachen Schritten zum mobilen PC mit Paragon Drive Copy 10 und Microsoft Windows Virtual PC

Klausur zur Einführung in die objektorientierte Programmierung mit Java

Einführung in die Informatik Tools

Einführung in die Java- Programmierung

Mit der Maus im Menü links auf den Menüpunkt 'Seiten' gehen und auf 'Erstellen klicken.

Musterlösung zur Vorlesung Modellbasierte Softwareentwicklung Wintersemester 2014/2015 Übungsblatt 9

Kommunikations-Management

Anwendungspraktikum aus JAVA Programmierung im SS 2006 Leitung: Albert Weichselbraun. Java Projekt. Schiffe Versenken mit GUI

5.2 Neue Projekte erstellen

Autorisierung. Sicherheit und Zugriffskontrolle & Erstellen einer Berechtigungskomponente

Kap. 35 Swing: Grundlagen Kap Swing: Hauptfenster

Nach der Installation kann es auch schon losgehen. Für unseren Port Scanner erstellen wir zunächst ein neues Projekt:

8 Design Patterns. Events

Modul 2: Automatisierung des Posteingangs - Regel- und Abwesenheits-Assistent

Handbuch ECDL 2003 Basic Modul 5: Datenbank Grundlagen von relationalen Datenbanken

2. Einrichtung der ODBC-Schnittstelle aus orgamax (für 32-bit-Anwendungen)

1. Software installieren 2. Software starten. Hilfe zum Arbeiten mit der DÖHNERT FOTOBUCH Software

Lizenzen auschecken. Was ist zu tun?

Anwendungsbeispiele Buchhaltung

WhiteStarUML Tutorial

Praktikum IKT 3. Semester

Anleitung zur Verwendung der VVW-Word-Vorlagen

Datensicherung. Beschreibung der Datensicherung

Klausur WS 2006/07 Programmiersprache Java Objektorientierte Programmierung II 15. März 2007

Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung: Lösungsvorschlag

Informatik Kurs Simulation. Hilfe für den Consideo Modeler

Mediator 9 - Lernprogramm

Erstellen eines Screenshot

Microsoft Access 2010 Navigationsformular (Musterlösung)

DFBnet Postfachsystem Signatur, Automatische Antwort, Weiterleitung

Transkript:

Seminar Entwurfmuster Chain of Responsibility (Zuständigkeitskette) Betreuende Professoren Prof. Dr. B. Renz Prof. Dr. W. Henrich Fachhochschule Giessen-Friedberg Studiengang Informatik Stand: 17. Juni 2003

Inhaltsverzeichnis 1 Ein kurze Einführung 3 1.1 Der Nutzen von Entwurfsmustern (Pattern)................ 3 1.2 Die Gruppe der Verhaltensmuster (Behavioral Pattern).......... 3 2 Chain of Responsibility - Zuständigkeitskette 4 2.1 Motivation................................... 4 2.2 Layoutanpassung mit der Zuständigkeitskette............... 5 2.3 Ein schnelles Beispiel............................. 5 2.4 Allgemeine Struktur............................. 7 2.5 Die Zuständigkeitskette im Beispiel..................... 7 2.6 Weitere Beispiele in der Praxis........................ 10 3 Verschiedene Aspekte der Zuständigkeitskette 11 3.1 Konsequenzen der Zuständigkeitskette................... 11 3.2 Nachrichtenkodierung............................. 11 3.3 Strukturen und Strategien.......................... 12 3.4 Die Verbindung zu anderen Mustern.................... 12 4 Bewertung der Entwurfmuster 13 4.1 Anwendbarkeit der Zuständigkeitskette................... 13 4.2 Mit Entwurfmustern zu besserer Software?................. 13 Quellenverzeichnis 14 Anhang 15 A Quellcode zum Einführungsbeispiel 15 B Quellcode des Beispiels zur Layoutanpassung 17 Zusammenfassung Diese Ausarbeitung soll einen Überblick über das Entwurfsmuster Chain of Responsibility geben. Anhand eines Beispiels soll die Verwendung und den Zweck des Musters erläutert werden. Dabei werden die Konsequenzen und einige Probleme, die während der Implementierung auftreten, angesprochen und Lösungsvorschläge angeführt. Dem Leser soll das Bewustsein geschärft werden, bei der Lösung verschiedener Softwareprobleme den Einsatz von Entwurfmustern, insbesondere des Musters Chain of Responsibility, genau abzuwägen, um so gut strukturierte Software zu schreiben.

Ein kurze Einführung Seite 3 1 Ein kurze Einführung Entwurfmuster gewinnen seit einigen Jahren immer mehr an Bedeutung und werden oft schon mit erfolgreicher Softwareentwicklung gleichgesetzt. Entwurfsmuster, engl. Design Patterns, werden in drei Gruppen aufgeteilt, die verschiedene Bereiche des objektorientierten Designs behandeln. Dabei werden Erzeugungsmuster, Strukturmuster und Verhaltensmuster unterschieden. 1.1 Der Nutzen von Entwurfsmustern (Pattern) Entwurfsmuster beschreiben Lösungen für wiederkehrende Probleme in der Entwicklung objektorientierter Systeme. Sie liefern Entwicklern Ansätze bestimmte Probleme mit Hilfe von Mustern zu lösen. Dabei wird die Struktur gleichartiger Probleme vereinheitlicht und die Wartbarkeit von Programmen erleichtert. Entwurfmuster sollen dem Entwickler auch schon beim Entwurf von Softwaresystemen helfen, durch den geschickten Einsatz verschiedener Muster, qualitativ höherwertige Software zu schreiben. Das Standardwerk für Entwurfmuster Design Patterns der GoF, Gang of Four, (siehe [GHJV-EM]) erläutert 23 verschiedene Entwurfmuster. Die Entwurfmuster selbst werden dabei bestehend aus vier Teilen beschrieben. Mustername - beschreibt Problem, Lösung und Konsequenz in wenigen Worten Problemabschnitt - erläutert den Kontext in dem das Muster zum Einsatz kommt Lösungsabschnitt - beschreibt Struktur, Verhalten und Beziehungen der Elemente, die das Muster ausmachen Konsequenzabschnitt - wägt die Vor- und Nachteile des Musters ab und erläutert seinen entgültigen Nutzen 1.2 Die Gruppe der Verhaltensmuster (Behavioral Pattern) Das im folgenden beschriebene Entwurfsmuster Chain of Responsibility zählt zu den Verhaltensmustern. Diese beschreiben nicht nur die Struktur von Klassen oder Objekten, sondern vor allem die Interaktion untereinander. So können komplexe Kontrollflüsse mit Hilfe der Interaktion der Objekte einfacher erklärt werden. Dabei befassen sich Verhaltensmuster auch mit Algorithmen und der Zuweisung von Zuständen. Zur Gruppe der Varhaltensmuster gehören verschieden Muster, die hier nur mit ihrem Namen aufgeführt werden: Befehl, Beobachter, Besucher, Interpreter, Iterator, Schablonenmethode, Strategie, Vermittler, Zustand und natürlich auch die Zuständigkeitskette.

Chain of Responsibility - Zuständigkeitskette Seite 4 2 Chain of Responsibility - Zuständigkeitskette Das Entwurfsmuster der Zuständigkeitskette wird von der Gang of Four wie folgt definiert [GHJV-EM]: Vermeide die Kopplung des Auslösers einer Anfrage mit seinem Empfänger, indem mehr als ein Objekt die Möglichkeit erhält, die Aufgabe zu erledigen. Verkette die empfangenden Objekte und leite die Anfrage an einer Kette entlang, bis ein Objekt sie erledigt. Die Aufgabe der Zuständikeitskette definiert Stephen Stelting [SSOM-AJP]: Führe eine Kette in einem System ein, damit Nachrichten entweder dort behandelt werden, wo sie empfangen wurden oder an ein Objekt weiterleitet werden, welches die Nachricht bearbeiten kann. 2.1 Motivation Die Zuständigkeitskette versucht die Kopplung von Objekten zu verringern, indem eine Aufgabe in einer Kette von Objekten bearbeitet wird. Man stelle sich ein Unternehmen vor, das aus einem Vorstand, Abteilungsleitern und Sekretärinnen besteht. Das folgende Klassendiagramm verdeutlicht die Struktur. Abbildung 1: Das Firmenmodell als Klassendiagramm Eine Sekretärin einer kleinen Abteilung erhält eine Anfrage über die Vertiefung künftiger Kundenbeziehungen. Sie kann sie nicht bearbeiten, weil sie keine Entscheidungskompetenzen hat. Also wird dem Abteilungsleiter diese Anfrage wietergegeben. Da er über die künftigen Bezeihungen des Kunden, z.b. ein wichtiger Großkunde, nicht entscheiden darf, leitet auch er die Anfrage an die Sekretärin seines Vorgesetzen weiter. Diese gibt Sie wiederum an ihren Vorgesetzten. Da dieser Kunde für eine erfolgreiche Zukunft des Unternehmens von großer Bedeutung ist, wird schließlich der Vorstand in die Entscheidungsfindung mit eingebunden.

Chain of Responsibility - Zuständigkeitskette Seite 5 Die Anfrage wurde also anhand einer Kette weitergeben, ohne dass die erste Sekretärin wusste, dass die Anfrage beim Vorstand landen würde. Wäre die Anfrage vielleicht von einem Kleinkunden oder Privatmann eingegangen, hätte der Abteilungsleiter selber die Anfrage bearbeiten können, ohne sie Richtung Führungsspitze weiterleiten zu müssen. Abbildung 2: Bearbetungsmodell der Anfrage Alle Anfragen werden also immer an den Vorgesetzen in dieser Kette weitergeleitet, bis einer sie bearbeitet. Die Kopplung für die Bearbeitung der Aufgabe ist gelockert. Der genaue Aufbau der Klassen und Objekte sowie ihre Rolle in der Zuständigkeitskette soll nun an einem weiterem Beispiel verdeutlicht werden. 2.2 Layoutanpassung mit der Zuständigkeitskette Die Zuständigkeitskette kann in Verbindung mit grafischen Benutzeroberflächen (kurz: GUI) genutzt werden. Die Elemente einer Benutzeroberfläche, wie Fenster, Dialoge, Eingabefelder oder Buttons sind in C# Spezialisierungen der Klasse Component und können wiederum weitere Components enthalten. So ergibt sich eine Baumstruktur. Wird zum Beispiel die Hintergrundfarbe des Hauptfensters geändert, werden alle abhängigen Komponenten ebenfalls angewiesen die Hintergrundfarbe zu ändern. Die Nachricht wird also von der Wurzel der Baumstruktur zu den einzelnen Blättern weitergegeben. Die Zuständigkeitskette kann nun dazu benutzt werden, Nachrichten in anderer Richtung von den Blättern bis zur Wurzel weiterzuleiten. Das Beispielprogramm soll nun sein Aussehen des GUIs ändern, je nach dem, was der Benutzer einstellt. Im folgenden werden zwei Programme vorgestellt, die das Problem mit und ohne Zuständigkeitskette lösen, um die Unterschiede, Vor- und Nachteile ansprechen zu können. 2.3 Ein schnelles Beispiel Das erste Programm zur Änderung des Layouts, gibt dem Benutzer die Möglichkeit über RadioButtons und Buttons verschiedene Einstellungen an der Oberfläche vorzunehmen (siehe Abb. 3). Zum Einem kann die Hintergrundfarbe eines Panels, der die ganzen Einstellbuttons enthält, geändert werden. Das Clientfenster kann Bilder anzeigen und der Text der Titelzeile kann über einen Button ausgetauscht werden.

Chain of Responsibility - Zuständigkeitskette Seite 6 Die gesamte Anwendung wird von einer Klasse repräsentiert, die von Form abgeleitet ist und das Hauptfenster darstellt. Sie enthält alle weiteren GUI-Objekte und initialisiert die Oberfläche. Die Event-Behandlung in C# stellt sich recht einfach dar, indem einer Komponente eine spezielle private Methode der Hauptfensterklasse als Eventhandler zugewiesen wird. Eine solche Methode sieht wie folgt aus. private void radiobutton4_checkedchanged(object sender, EventArgs e) panel1.backcolor = System.Drawing.Color.Blue; Wird der Radiobutton4 angewählt, wird ein Event erzeugt und an alle Eventhandler dieses Radiobuttons weitergeleitet. Da nur dieser Eventhandlerfunktion zur Verfügung steht, wird der Code ausgeführt. Dabei die die Hintergrundfarbe des vorhin angesprochenden Panel auf Blau geändert. Alle anderen Event-Methoden sehen ähnlich aus. Abbildung 3: Screenshot der Beispielprogramms Unschwer ist die enge Kopplung der Radiobuttons zu dem Panel zu sehen. Die anderen Radiobuttons, die ebenfalls die Hintergrundfarbe ändern wollen, greifen ebenfalls in enger Kopplung auf die Eigenschaften des Panels zu. Soll nun die Farbe einer anderen Komponente z.b. des Hauptfensters geändert werden, müssten alle Event-Methoden, welche die Farbe des Panels ändern, angepasst werden. Nun könnte es unter bestimmten Umständen nicht erwünscht sein, dass Eigenschaften von außen geändert werden sollen. Dass heißt, das Objekt selbst soll entscheiden, ob es seine Eigenschaften ändern will oder nicht. In einem dynamischen System, wo sich die Verbindungen zwischen einzelnen Komponenten zur Laufzeit ändern können, würde eine feste Kopplung die Dynamik des System schwer beeinträchtigen. Hier kann die Zuständigkeitskette aushelfen.

Chain of Responsibility - Zuständigkeitskette Seite 7 2.4 Allgemeine Struktur Kommen wir zunächst zum allgmeinen Aufbau der Chain of Responsibility, bevor wir das geänderte Beispiel näher betrachten. Das Klassendiagramm in Abb. 4 zeigt die Struktur der Zuständigkeitskette. Den Mittelpunkt des Musters bildet die abstrakte Klasse Handler. Sie definiert eine abstrakte Methode handle(), die alle abgeleiteten Klassen implementieren müssen. Der Handler verwaltet die Referenz auf das Nachfolger- Objekt, das die Weiterverarbeitung in der Kette übernimmt. Abbildung 4: Chain of Responsibility (Quelle: [GHJV-EM]) Die abgeleitenten Klassen Handler1 und Handler2 implementieren nun das Verhalten der einzelnen Objekte in der Kette. Der Client löst eine Anfrage an irgendeiner Stelle der Kette aus und ruft dabei die Bearbeitungsmethode handle() des Kettenobjektes auf. Wenn dieses die Anfrage nicht oder nur teilweise bearbeiten kann, wird die Anfrage an das Nachfolgerobjekt in der Kette weitergeleitet. Je nachdem, ob die Anfrage bearbeitet werden kann, wird die handle()-methode des Nachfolgerobjekts aufgerufen oder nicht. Die Weiterleitung wird beendet, bis ein Element der Kette die Anfrage bearbeiten konnte oder die Kette zu Ende ist. Die Chain of Responsibility bietet also keine Abarbeitungsgarantie. Es wird nur garantiert, dass eine Anfrage, die von einem Element nicht bearbeitet werden konnte, an das Nachfolgeelement weitergegeben wird. 2.5 Die Zuständigkeitskette im Beispiel Für verschiedene Implementierungsaspekte wollen wir nun das Beispiel von vorhin aufgreifen und mit Hilfe einer Zuständigkeitskette realisieren. Zunächst muss eine abstrakte Klasse eingeführt werden, von der alle Elemente der Kette erben müssen. Hier ergibt sich ein Problem der fehlenden Mehrfachvererbung in C#. Die einzelnen Elemente müssen von den GUI-Klassen erben, damit sie die gleiche Funktionalität wie vorher besitzen. Das Problem wird mit dem Einsatz eines Interfaces anstatt einer abstrakten Klasse umgangen. Im Interface LayoutHandler wird die Bearbeitungsmethode handlelayoutchange() der Kette vorgeschlagen. Die einzelnen Objekte der

Chain of Responsibility - Zuständigkeitskette Seite 8 Kette müssen nun diese Schnittstelle einhalten. Die Benutzung eines Interface beeinträchtig nicht den Aufbau oder die Benutzung der Zuständigkeitskette. Abbildung 5: Klassendiagramm zum Beispielprogramm Am eigentlichen Programm ändert sich nicht viel. Anstatt der normalen GUI Klassen, wie From, Panel oder RadioButton, werden die spezialisierten Klassen, wie MainWnd, ColorPanel oder RadioBtn, verwendet. Diese implementieren noch zusätzlich die Bearbeitungsmethode des Interfaces LayoutHandler. Eine geänderte Klasse sieht dann wie folgt aus: public class RadioBtn : RadioButton, LayoutHandler private LayoutHandler successor; public RadioBtn(LayoutHandler successor) this.successor = successor; public virtual void handlelayoutchange(layoutproperty property) // deliver to successor handler if(successor!= null) successor.handlelayoutchange(property); Im Konstruktor wird eine Referenz auf das Nachfolgeobjekt übergeben, so das evtl. Anfragen weitergeleitet werden können. Die Bearbeitungsmethode handlelayoutchange() bearbeitet die Anfrage. Hier wird die Anfrage direkt an den Nachfolger weitergeleitet. Die Klasse MainWnd übernimmt sowohl die Funktion des Clients als auch das Ende der Kette. Ihre handlelayoutchange()-methode ist leer implementiert, so dass die Kette hier spätestens abbricht. Die Inititalisierung der Zuständigkeitskette wird von MainWnd erledigt. Hier ein paar Codezeilen aus der Inititalisierungsprozedur: this.imagewnd = new ImageWnd(this); this.colorpanel = new ColorPanel(this.imageWnd); this.radioboxcolor = new RadioBox(this.colorPanel); this.radiobuttongreen = new RadioBtn(this.radioBoxColor);

Chain of Responsibility - Zuständigkeitskette Seite 9 Die Eventhandler-Methoden der Hauptklasse MainWnd werden nun als Einstiegspunkte in die Zuständigkeitskette realisiert. Während im Beispiel ohne Zuständigkeitskette dort direkt die Änderung der Eigenschaften verschiedener Fensterobjekte programmiert wurden, erhält nun das Fensterobjekt, zu dem der Eventhandler gehört, die Aufgabe, die Anfrage zu bearbeiten. private void radiobuttonblue_checkedchanged(object sender, EventArgs e) LayoutProperty lp = LayoutProperty("Blue", LayoutProperty.BACKGROUND); radiobuttonblue.handlelayoutchange(lp); Ob nun der RadioButton die Aufgabe erledigt oder in der Kette weiterleitet, ist für den Client nun nicht mehr sichtbar. Die Kopplung zwischen RadioButton und Panel, wie im ersten Beispiel, wurde aufgelöst. Ob nun das Panel die Nachricht erhält und bearbeitet, kann nicht mehr garantiert werden. Dafür muss die Zuständigkeitskette entsprechend aufgebaut werden, damit die Anwendung sich genauso verhält, wie die erste Lösung. Wird nun eine Event ausgelöst und ein Element angewiesen, die Anfrage zu bearbeiten, wird eine Bearbeitungskette angestoßen, die sich durch folgendes Sequenzdiagramm darstellt. Abbildung 6: Sequenzdiagramm einer Zusändigkeitskette Ein Radiobutton wird über einen Klick auf den Button vom Client angewiesen, die Anfrage zu bearbeiten. Die Anfrage wird mit einer Nachricht kodiert, die von der Klasse LayoutPropery repräsentiert wird. Die Nachrichtenobjekte werden durch einen Typ und einer Nachricht spezifiziert (siehe Abb. 5). Mit verschiedenen Ansätzen zur Nachrichtenkodieren befasst sich später das Kapitel 3.2. Anhand des Typs entscheidet nun der einzelne Bearbeiter in der Kette, ob er die Anfrage bearbeiten kann oder nicht. Das Beispiel im Sequenzdiagramm zeigt eine Situation, in der die Anfrage bis zum Hauptfenster weitergeleitet werden muss, weil kein Bearbeiter die Anfrage zuvor ausreichend bearbeiten konnte.

Chain of Responsibility - Zuständigkeitskette Seite 10 Die Fensterelemente sind in diesem Beispiel als Baum angeordnet, wie es bei grafischen Benutzeroberflächen üblich ist. Daher bietet es sich an, mehrere Zuständigkeitesketten, beginnend bei jedem Blatt im Baum, zu realisieren. Für dieses Beispiel musste im Fall des Panels, die Kette über die PictureBox umgeleitet werden, damit Anfragen, die an verschiedene Buttons gestellt werden, von der PictureBox bearbeitet werden können. Beispiele für andere Ausprägungen der Kette werden später diskutiert. Abbildung 7: Chain of Responsibility in einem Baum 2.6 Weitere Beispiele in der Praxis In den angeführten Beispielen haben wir schon zwei Anwendungsgebiete der Chain of Responsibility gesehen. Sie eignet sich besonders für verschiedene Aktivitäten eines GUIs, wie Formatieren oder Positionieren von Komponenten. In der Praxis wird sie bei der Nachrichtenbehandlung angewandt. Das ET++ Framework, ein objektoriertiertes Programmiersystem in C++, realisiert die Aktualisierung des Bildschirm über Zuständigkeitsketten. In Java werden viele Event-Handler als Kette realisiert, damit alle Objekte auf einen Event reagieren können. Die Nachrichtenbehandlung in Windows wird ebenfalls als Kette realisert, indem alle Nachrichtenfunktionen nacheinander aufgerufen werden und entsprechende Funktionen ausführen. Da dort keine Objektmodell verwendet wird, kann man nicht von einer Zuständigkeitskette sprechen.

Verschiedene Aspekte der Zuständigkeitskette Seite 11 3 Verschiedene Aspekte der Zuständigkeitskette Dieses Kapitel bespricht die Vorteile, Verpflichtungen und Besonderheiten der Zuständigkeitskette. Einige implementierungsspezifischen Aspekte sollen näher betrachtet werden. Da Entwurfmuster nur selten alleine auftreten, soll das Zusammenspiel mit verschieden Mustern näher beleuchtet werden. 3.1 Konsequenzen der Zuständigkeitskette Die Verwendung der Zuständigkeitskette bringt für die Softwareentwicklung einige Vorteile, aber auch Verpflichtungen mit, die sich wie folgt gliedern: Reduzierte Kopplung Ein Objekt muss nicht mehr wissen, welches Objekt die Anfrage bearbeitet. Dadurch ist es möglich, Objektbeziehungen zu vereinfachen. Die Anfrage wird nur in der Kette weitergegeben, bis sie bearbeitet wird, dabei ist die Struktur der Kette für die einzelnene Objekte nicht relevant. Höhere Flexibilität Die Zuständigkeiten können leicht verändert werden, indem Objekte der Kette gelöscht oder neue Objekte eingefügt werden. So kann zur Laufzeit die Stuktur der Kette beliebig geändert und das Verhalten des Systems beeinflusst werden. Keine Abarbeitungsgaratie Da die Objekte eine Anfrage an einen Nachfolger wieterleiten, kann nicht garantiert werden, dass die Anfrage auch wirklich bearbeitet wird. 3.2 Nachrichtenkodierung Anfragen in der Zuständigkeitskette werden im Normalfall durch einen Methodenaufruf realisiert. Falls die Bearbeiterobjekte verschiedene Aufgaben erledigen können, ist es am einfachsten, verschiedene Methoden zu definieren, welche die Aufgaben erledigen. Dies ist aber wenig flexibel, da die Anzahl der Aufgaben auf die Anzahl der Methoden begrenzt wird. Soll die Kette um eine weitere Aufgabe erweitert werden, müssen alle existierenden Bearbeiter Klassen diese Methode implementieren. Einfacher ist es nur eine einzige Bearbietermethode zu definieren, die einen Parameter enthält. Wenn unterschiedliche Parameter benötig werden, bietet es sich an, eine Anfrageobjekt einzuführen. Im Beispiel wurde dazu die Klasse LayoutProperty verwendet, um eine Anfrage zu kodieren. Mit Hilfe festgelegter Typen und einer Nachricht, können die Bearbeiter entscheiden, ob sie die Anfrage bearbeiten können. Kann das Objekt die Anfrage bearbeiten, wird die Nachricht ausgewertet und entsprechender Code ausgeführt. Kann die Anfrage nicht bearbeitet werden, wird sie einfach an den Nachfolger in der Kette weitergegeben.

Verschiedene Aspekte der Zuständigkeitskette Seite 12 3.3 Strukturen und Strategien In den Beispielen wurde die Zuständigkeitskette in einem Baum verwendet. Die Zuständigkeitskette kann aber auch in linearer Abfolge alle möglichen Bearbeiter durchlaufen, bis die Anfrage bearbeitet wird. Auch Implementierungen als Ring sind denkbar. Wie eine Zuständigkeitskette aufgebaut wird, muss der Entwickler abwägen. Die Abbildung 8 zeigt eine lineare Struktur. Abbildung 8: Chain of Responsibility als lineare Kette Mit zunehmender Länge einer Kette handelt man sich aber vielleicht zusätzliche Probleme ein. Fehler im Laufzeitverhalten können nur schwer gefunden werden, vor allem wenn die Struktur der Kette variabel ist. Um späteren Problemen vorzubeugen, können verschiedene Implentierungs-Strategien benutzt werden. Bearbeite jede Nachricht, die nicht zur Wieterleitung spezifiziert ist Leite jede Anfrage weiter, die nicht zur Bearbeitung gekennzeichnet ist Jede Nachricht, die nicht bearbeitet werden kann, leite zum Standardbearbeiter Jede Anfrage, die werder bearbeitet noch wietergeleitet werden soll, wird ignoriert 3.4 Die Verbindung zu anderen Mustern Die Chain of Responsibility kann zusammen mit dem Muster Composite eingesetzt werden. Das Elternobjekt wird in der Kette als Nachfolgerobjekt verwendet. Das Kompositum erstellt eine Baumstruktur in dem die Zuständigkeitskette die Nachrichtenfunktion übernimmt. Während beim Kompositum die Nachrichten von der Wurzel zu den Blätter wandern, wird der umgekehrte Weg über die Zuständigkeitskette geregelt. Im Buch von J. W. Cooper ([SWC-IDPC]) wird ein Beispiel einer Zuständigkeitskette mit dem Interpretermuster betrachtet.

Bewertung der Entwurfmuster Seite 13 4 Bewertung der Entwurfmuster Es gibt viele Meinungen, wie gute Software auszusehen hat. Die 23 Entwurfsmuster, die Erich Gamma und wietere herausgestellt haben, sind aus wiederkehrenden Problemstellungen und Lösungen in Softwaresystemen entstanden. Heute existiern noch eine gnaze Reihe neuer Muster und Varienten von Mustern, die versuchen, für verschiedene Problemstellungen Lösungsansätze bereitzustellen. Das hier angesprochene Muster Chain of Responsibility will feste Objektbeziehungen auflösen und durch einfache Kettenstrukturen ersetzten, damit das System mehr Dynamik erhält, aber dennoch wartbar und wiederverwendbar bleibt. 4.1 Anwendbarkeit der Zuständigkeitskette In dieser Ausarbeitung wurden mehrere Situationen vorgestellt, wo die Zuständigkeitskette eingesetzt werden kann. Sie dient dazu, die Kopplung der Objekte zu verringern und Wiederverwendbarkeit von Softwareteilen zu erhöhen. Dafür ist das Entwickeln und Testen bei größeren Systemen schwieriger. Der Entwickler muss also abwägen, ob die Verwendung der Zuständigkeitskette einen Nutzen bringt. Im Allgemeinen wird sie immer da eingesetzt werden, wo Nachrichten von Objekten gesendet und empfangen werden. Durch ihre einfache Handhabung und Verkettungsmöglichkeiten ist die Zuständigkeitskette besonders in dynamischen Laufzeitsystemen einsetzbar. Untersuchungen zeigen, dass der Einsatz der Zuständigkeitskette im Bezug auf die Performance kleinerlei Einschränkung darstellt ([FHI-EP]). Auch wenn sie in der Praxis nur selten Anwendung findet, sollte der Entwickler beim Design immer ein Auge auf die Zuständigkeitskette werfen. 4.2 Mit Entwurfmustern zu besserer Software? Entwurfsmuster werden schon seit Jahren erfolgreich beim objektorientieren Entwurf eingesetzt. Sie helfen Software übersichtlicher zu gestalten und mit erprobten Mustern schon Fehler beim Entwurf zu vermeiden. Zudem erhöhen Sie Wartbarkeit und Wiederverwendebarkeit der Software. Wer sowieso schon gut strukturiert Software schreibt, wird in seinem Quellcode immer wieder die Verwendung verschiedener Entwurfsmuster entdecken. Bei rein objektorientierten Sprachen, wie C#, Java oder Smalltalk, bieten Muster ein gutes Handwerkszeug für den Entwickler, um Probleme einfacher und effizienter zu lösen.

LITERATUR Seite 14 Literatur [GHJV-EM] Dr. E. Gamma, Dr. R. Helm, Dr. R. Johnson, Dr. J. Vlissides Entwurfsmuster - Elemente wiederverwendbarer objektorientierter Software, 4. Auflage, deutsche Übersetzung von D. Riehle Addison-Wesley, Bonn 1996 [SSOM-AJP] Stephen Stelting, Olav Massen Applied Java Patterns Sun Microsystems, Inc., 2002 [SWC-IDPC] James W. Cooper Introduction to Design Patterns in C# IBM T J Watson Research Center, 2002 [FHI-EP] Fraunhofer Institut Entwurfsmuster und Performance http://genesis.iitb.fhg.de/servlet/is/2541/, 10.06.2003

Quellcode zum Einführungsbeispiel Seite 15 Anhang A Quellcode zum Einführungsbeispiel public class Firma : System.Windows.Forms.Form private System.Windows.Forms.NumericUpDown numericupdown1; private System.Windows.Forms.Label label1; private System.Windows.Forms.Button button1; private System.Windows.Forms.TextBox textbox1; private System.Windows.Forms.Label label2; Vorstand v; Abteilungsleiter a2; Sekretärin s2; Abteilungsleiter a1; Sekretärin s1; private System.ComponentModel.Container components = null; public Firma() InitializeComponent(); initchain(); protected override void Dispose( bool disposing )... private void InitializeComponent()... private void initchain() v = new Vorstand("Vorstand"); a2 = new Abteilungsleiter("Abteilungsleiter2",70, v); s2 = new Sekretärin("Sekretärin2",20, a2); a1 = new Abteilungsleiter("Abteilungsleiter1",40, s2); s1 = new Sekretärin("Sekretärin1",10, a1); static void Main() Application.Run(new Form1()); private void button1_click(object sender, System.EventArgs e) decimal stufe = numericupdown1.value; s1.bearbeiteanfrage(decimal.toint32(stufe), textbox1.text); public abstract class Personal protected int bearbeitungsstatus; protected Personal vorgesetzer; protected string name; public abstract void bearbeiteanfrage(int stufe, string nachricht);

Quellcode zum Einführungsbeispiel Seite 16 public class Vorstand : Personal private Personal[] mitarbeiter; public Vorstand(string name) this.bearbeitungsstatus = 100; this.vorgesetzer = null; this.name = name; public Personal[] Mitarbeiter get return mitarbeiter; set mitarbeiter = value; public override void bearbeiteanfrage(int stufe, string nachricht) System.Windows.Forms.MessageBox.Show(this.name + " bearbeite: " + nachricht + "\n"); public class Abteilungsleiter : Personal private Personal[] al; public Abteilungsleiter(string name, int bearbeitungsstatus, Personal vorgesetzer) this.bearbeitungsstatus = bearbeitungsstatus; this.vorgesetzer = vorgesetzer; this.name = name; public Personal[] Al get return al; set al = value; public override void bearbeiteanfrage(int stufe, string nachricht) if(stufe <= this.bearbeitungsstatus) MessageBox.Show(this.name + " bearbeite: " + nachricht + "\n"); else MessageBox.Show(this.name + " weiterleiten: " + nachricht + "\n"); vorgesetzer.bearbeiteanfrage(stufe, nachricht); public class Sekretärin : Personal public Sekretärin(string name, int bearbeitungsstatus, Personal vorgesetzer) this.bearbeitungsstatus = bearbeitungsstatus; this.vorgesetzer = vorgesetzer; this.name = name; public override void bearbeiteanfrage(int stufe, string nachricht) if(stufe <= this.bearbeitungsstatus) MessageBox.Show(this.name + " bearbeite: " + nachricht + "\n"); else MessageBox.Show(this.name + " weiterleiten: " + nachricht + "\n"); vorgesetzer.bearbeiteanfrage(stufe, nachricht);

Quellcode des Beispiels zur Layoutanpassung Seite 17 B Quellcode des Beispiels zur Layoutanpassung public class MainWnd : System.Windows.Forms.Form, LayoutHandler // Fensterobjekte private ImageWnd imagewnd; private RadioBox radioboxcolor; private RadioBtn radiobuttongreen; private RadioBtn radiobuttonred; private RadioBtn radiobuttonblue;... public MainWnd() InitializeComponent(); public virtual void handlelayoutchange(layoutproperty property) // Ende der Zustaendigkeitskette return; private void InitializeComponent() // Fensterinitialiserungen this.imagewnd = new ImageWnd(this); this.colorpanel = new ColorPanel(this.imageWnd); this.radioboxcolor = new RadioBox(this.colorPanel); this.radiobuttongreen = new RadioBtn(this.radioBoxColor); this.radiobuttonred = new RadioBtn(this.radioBoxColor); this.radiobuttonblue = new RadioBtn(this.radioBoxColor);... static void Main() System.Windows.Forms.Application.Run(new MainWnd()); private void buttonexit_click(object sender, System.EventArgs e) System.Windows.Forms.Application.Exit(); private void radiobuttonimage1_checkedchanged(object sender, System.EventArgs e) radiobuttonimage1.handlelayoutchange(new LayoutProperty("Sofi.jpg", LayoutProperty.IMAGE)); private void radiobuttonimage2_checkedchanged(object sender, System.EventArgs e) radiobuttonimage2.handlelayoutchange(new LayoutProperty("Karibik.jpg", LayoutProperty.IMAGE)); private void radiobuttonimage3_checkedchanged(object sender, System.EventArgs e) radiobuttonimage3.handlelayoutchange(new LayoutProperty("Wiese.jpg", LayoutProperty.IMAGE)); private void radiobuttonblue_checkedchanged(object sender, System.EventArgs e) radiobuttonblue.handlelayoutchange(new LayoutProperty("Blue", LayoutProperty.BACKGROUND)); private void radiobuttonred_checkedchanged(object sender, System.EventArgs e) radiobuttonred.handlelayoutchange(new LayoutProperty("Red", LayoutProperty.BACKGROUND)); private void radiobuttongreen_checkedchanged(object sender, System.EventArgs e) radiobuttongreen.handlelayoutchange(new LayoutProperty("Green", LayoutProperty.BACKGROUND)); private void messagebutton_click(object sender, System.EventArgs e) messagebutton.handlelayoutchange(new LayoutProperty("Nachricht", LayoutProperty.MESSAGE));

Quellcode des Beispiels zur Layoutanpassung Seite 18 // the handler interface public interface LayoutHandler // the handle method in the Chain of Responsibility void handlelayoutchange(layoutproperty property); // message object public class LayoutProperty //Konstanten public static int BACKGROUND = 1; public static int IMAGE = 2; public static int MESSAGE = 3; // Variablen private int type; private string message; public LayoutProperty(string message, int type) this.message = message; this.type = type; public string getmessage() return message; public int gettype() return type; public class ColorPanel : System.Windows.Forms.Panel, LayoutHandler private LayoutHandler successor; public ColorPanel(LayoutHandler successor) this.successor = successor; public virtual void handlelayoutchange(layoutproperty property) if(property.gettype() == LayoutProperty.BACKGROUND) // Change Background-Color if(property.getmessage() == "Red") this.backcolor = System.Drawing.Color.Red; else if(property.getmessage() == "Green") this.backcolor = System.Drawing.Color.Green; else if(property.getmessage() == "Blue") this.backcolor = System.Drawing.Color.Blue; else // deliver to successor handler if(successor!= null) successor.handlelayoutchange(property);

Quellcode des Beispiels zur Layoutanpassung Seite 19 public class ImageWnd : System.Windows.Forms.PictureBox, LayoutHandler private LayoutHandler successor; public ImageWnd(LayoutHandler successor) this.successor = successor; public virtual void handlelayoutchange(layoutproperty property) if(property.gettype() == LayoutProperty.IMAGE) // Load a new Image System.Drawing.Image image = System.Drawing.Image.FromFile(property.getMessage()); this.image = new System.Drawing.Bitmap(image, this.size); else // deliver to successor handler if(successor!= null) successor.handlelayoutchange(property); public class RadioBox : System.Windows.Forms.GroupBox, LayoutHandler private LayoutHandler successor; public RadioBox(LayoutHandler successor) this.successor = successor; public virtual void handlelayoutchange(layoutproperty property) // deliver to successor handler if(successor!= null) successor.handlelayoutchange(property); public class RadioBtn : System.Windows.Forms.RadioButton, LayoutHandler private LayoutHandler successor; public RadioBtn(LayoutHandler successor) this.successor = successor; public virtual void handlelayoutchange(layoutproperty property) // deliver to successor handler if(successor!= null) successor.handlelayoutchange(property); public class MessageBtn : System.Windows.Forms.Button, LayoutHandler private LayoutHandler successor; public MessageBtn(LayoutHandler successor) this.successor = successor; public virtual void handlelayoutchange(layoutproperty property) // deliver to successor handler if(successor!= null) successor.handlelayoutchange(property);