Benutzer-Werkzeuge

Webseiten-Werkzeuge


de:lehre:softwareentwicklung:buch:17:index

17. Entwurfsmuster (Patterns)

Themen
Zur Bedeutung von Mustern
Die „klassischen“ Entwurfsmuster in der Softwareentwicklung
Warum sollte man Entwurfsmuster kennen und einsetzen?
Der richtige Umgang mit Entwurfsmustern
Glossar
PDF
Kapitel bei Springer
https://link.springer.com/chapter/10.1007/978-3-662-71607-6_17


Zentrale Aspekte

  • Der Entwurf objektorientierter Software ist schwierig,
    und der wiederverwendbarer Software noch schwieriger.
  • Muster sind bewährte (abstrakte) Lösungen
    für wiederkehrende Fragestellungen.
  • Entwurfsmuster beschreiben interagierende Objekte und Klassen
    als maßgeschneiderte Lösung eines generellen Problems.
  • Klar benannte Entwurfsmuster ermöglichen die Entwicklung
    von Software auf einer höheren Abstraktionsebene.
  • Entwurfsmuster sind kein Selbstzweck.
    Sie können zu sparsam und zu freigiebig eingesetzt werden.

Zusammenfassung

Objektorientierte Software zu entwerfen ist schwierig. Noch schwieriger ist es, wiederverwendbare Software zu entwerfen. Die gute Nachricht: Wir müssen das Rad nicht neu erfinden, wenn wir uns darauf einlassen, von professionellen Softwareentwicklerinnen und Entwicklern zu lernen, die ihr Wissen sogar gut zugänglich aufgeschrieben haben. Entwurfsmuster sind eine dieser Quellen.

Ein Entwurfsmuster ist eine bewährte (abstrakte) Lösung für wiederkehrende Fragestellungen. Die Idee ist dabei, dass die konkrete Problemstellung zwar oft einmalig ist, das zu lösende Problem und eine bewährte Lösung in ihrer Struktur aber bekannt. Im Kontext der Softwareentwicklung beschreiben Entwurfsmuster miteinander interagierende Objekte und Klassen als maßgeschneiderte Lösung eines generellen Problems.

Ein großer Vorteil der bewussten Verwendung von Entwurfsmustern liegt darin, dass sie das verfügbare Vokabular um komplexe Zusammenhänge erweitern und so die Softwareentwicklung und die Kommunikation über den Code auf einer höheren Abstraktionsebene erlauben. Auch wenn Entwurfsmuster für viele Programmiererinnen und Programmierer in den Naturwissenschaften ganz am Ende stehen: wollen wir Software schreiben, die den Ansprüchen der Wissenschaft genügt und nicht trivial (und damit unbrauchbar) ist, werden wir um die Verwendung von Entwurfsmustern nicht umhin kommen.

Fragen zur Vertiefung und Wiederholung

Diese Fragen dienen der persönlichen Beschäftigung mit der Thematik, es werden aber keine Antworten zur Verfügung gestellt.

  • Welche zwei wesentlichen Aspekte eines Musters (sowohl nach Alexander als auch nach der „Viererbande“) lassen sich unterscheiden?
  • Wie unterscheiden sich Entwurfsmuster von Idiomen einerseits und der Architektur eines Softwareprojekts andererseits?
  • Was ist eine grundlegende Voraussetzung für die Nutzung der hier vorgestellten Entwurfsmuster?
  • Welche Vorteile sehen Sie in der Verwendung von Entwurfsmustern?
  • Warum ist es für den praktischen Einsatz wichtig, mit einem Katalog von Entwurfsmustern inhaltlich vertraut zu sein?
  • Warum sollte man ein Entwurfsmuster, wenn man es in einer konkreten Implementierung einsetzt, möglichst beim Namen nennen?

Beispiel: Das „Observer“-Entwurfsmuster

Im Rahmen des Buches wird ein Entwurfsmuster, das „Observer“-Entwurfsmuster, vorgestellt. Nachfolgend seien sowohl das Schema zur Motivation und das UML-Diagramm als auch eine mögliche Implementierung in Python wiedergegeben.

Abbildung 1: Beispiel für einen Anwendungsfall des „Observer“-Entwurfsmusters. Es gibt mehrere unterschiedliche Ansichten bzw. Darstellungsweisen von Daten, die in einem Objekt gespeichert sind. Das Datenobjekt sollte die Ansichten benachrichtigen, wenn sich die Daten ändern, die Ansichten können die Daten vom Datenobjekt abfragen und Änderungen der Daten (z.B. durch Nutzereingaben) an das Datenobjekt zurückmelden. Für ein UML-Diagramm des „Observer“-Entwurfsmusters, das zur Umsetzung dieser Situation verwendet werden kann, vgl. Abb. 2. Die Idee stammt aus [Gamma, 1995Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1995): Design Patterns. Elements of Reusable Object-Oriented Software, Addison-Wesley, Boston], S. 293
Abbildung 2: UML-Diagramm einer Realisierungsmöglichkeit des „Observer“-Entwurfsmusters. Es gibt zwei abstrakte Klassen (Subject und Observer) und zwei davon durch Vererbung abgeleitete konkrete Klassen (ConcreteSubject und ConcreteObserver). In einem Subject können beliebig viele Observer registriert werden, die dann bei einer Änderung benachrichtigt werden. Ein Observer beobachtet hingegen immer ein konkretes Subject und bezieht bei einer Benachrichtigung den aktuellen Zustand dieses Objektes. Das Diagramm ist gegenüber dem Beispiel in [Gamma, 1995Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1995): Design Patterns. Elements of Reusable Object-Oriented Software, Addison-Wesley, Boston] S. 294 vereinfacht, es stellt nur eine mögliche Realisierung dieses Entwurfsmusters dar. Ein konkretes Beispiel für einen möglichen Anwendungsfall ist in Abb. 1 dargestellt.

Eine mögliche Implementation des Observer-Entwurfsmusters in Python wird nachfolgend anhand konkreter Codebeispiele gezeigt. Diese Implementation folgt relativ strikt dem UML-Diagramm in Abb. 2.

Zunächst werden die beiden abstrakten Klassen Subject und Observer implementiert, von diesen Klassen erben dann in einem nächsten Schritt die konkreten Klassen ConcreteSubhject und ConcreteObserver.

class Subject():
    def __init__(self):
        self.observers = []
 
    def attach(self, observer=None):
        self.observers.append(observer)
 
    def notify(self):
        for observer in self.observers:
            observer.update()
 
class Observer():
    def __init__(self):
        self.observed_subject = None
 
    def update(self):
        self.observed_subject.get_state()

Inwieweit man, wie in diesem Beispiel und dem in Abb. 2 gezeigten UML-Diagramm folgend, die Methode get_state erst in der Klasse ConcreteSubject implementieren möchte oder aber bereits in der abstrakten Basisklasse Subject, um sie dann in der abgeleiteten Klasse zu überschreiben, ist nur eine der Fragen, die man unterschiedlich beantworten kann.

class ConcreteSubject(Subject):
    def __init__(self):
        super.__init__()
        self.state = None
 
    def get_state(self):
        return self.state
 
class ConcreteObserver(Observer):
    def update(self)
        super.update()
        # Update own internals
 
data_source = ConcreteSubject()
histogram_view = ConcreteObserver()
data_source.attach(observer=histogram_view)

Die Methode update der konkreten Klasse ConcreteObserver ruft erst einmal die Methode der Superklasse explizit auf und wird dann natürlich, abhängig vom jeweiligen Kontext, die eigenen Interna aktualsieren.

Die letzten drei Zeilen zeigen, wie man Instanzen der beiden konkreten Klassen erzeugen und diese dann miteinander verknüpfen kann. Natürlich wird man hier in der Praxis oft mehr als einen Beobachter für ein Subjekt haben. Die Stärke des Observer-Entwurfsmusters ist ja gerade, dass ein Subjekt sich von beliebig vielen Beobachtern beobachten lässt, ohne dass sich das beobachtete Subjekt um die Details kümmern muss.

Weiterführende Literatur

Eine kommentierte und handverlesene Liste mit weiterführender Literatur zum Thema. Die Auswahl ist zwangsläufig subjektiv.

Der „Klassiker“ zum Thema Entwurfsmuster ist mit Sicherheit das Werk der „Viererbande“: „Design Patterns“ von Gamma, Helm, Johnson und Vlissides [Gamma, 1995Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1995): Design Patterns. Elements of Reusable Object-Oriented Software, Addison-Wesley, Boston]. Ein Buch, das zwei wesentliche Konzepte der Entwicklung objektorientiert programmierter Software zusammenführt, ist „Refactoring to Patterns“ von Joshua Kerievsky [Kerievsky, 2005Kerievsky, Joshua (2005): Refactoring to Patterns, Addison-Wesley, Boston]. Er greift gleichermaßen auf das Werk der „Viererbande“ wie auf das grundlegende Werk zum Refactoring von Martin Fowler [Fowler, 1999Fowler, Martin (1999): Refactoring. Improving the Design of Existing Code, Addison-Wesley Longman, Boston] zurück.

Einen etwas anderen Ansatz als die „Viererbande“ verfolgt Kent Beck in „Implementation Patterns“ [Beck, 2007Beck, Kent (2007): Implementation Patterns, Addison-Wesley, Upper Saddle River, NJ]. Seine Muster decken einen wesentlich breiteren Bereich von Mustern ab als die hier vorgestellten Entwurfsmuster. Den Zusammenhang der schematischen Darstellung von Klassen und Objekten über UML und Entwurfsmustern thematisiert Craig Larman in „Applying UML and Patterns“ [Larman, 2005Larman, Craig (2005): Applying UML and Patterns, Prentice Hall, Upper Saddle River, New Jersey]. Weitere bekannte und oft zitierte Kataloge von Entwurfsmustern sind „Pattern-Oriented Software Architecture“ (POSA) [Buschmann, 1996Buschmann, Frank; Meunier, Regine; Rohnert, Hans; Sommerlad, Peter; Stal, Michael (1996): Pattern-Oriented Software Architecture. Volume 1: A System of Patterns, John Wiley & Sons, Chichester] und „Patterns of Enterprise Application Architecture“ (PoEAA) [Fowler, 2003Fowler, Martin (2003): Patterns of Enterprise Application Architecture, Addison Wesley, Boston]. Darüber hinaus gibt es noch eine ganze Reihe weiterer Werke, die sich mit dem einen oder anderen speziellen Aspekt bzw. Anwendungsgebiet von Mustern befasst [Beck, 2004Beck, Kent; Andres, Cynthia (2004): Extreme Programming Explained. Embrace Change, Addison-Wesley, Boston, Evans, 2004Evans, Eric (2004): Domain-Driven Design, Addison Wesley, Boston, Meszaros, 2007Meszaros, Gerard (2007): xUnit Test Patterns, Addison-Wesley, Boston].

Der Ausgangspunkt für die Beschäftigung mit Mustern in der Softwareentwicklung lieferte das Werk „A Pattern Language“ des Architekten, Mathematikers und Systemtheoretikers Christopher Alexander [Alexander, 1977Alexander, Christopher; Ishikawa, Sara; Silverstein, Murray (1977): A Pattern Language, Oxford University Press, New York].

  • Alexander, Christopher; Ishikawa, Sara; Silverstein, Murray (1977): A Pattern Language, Oxford University Press, New York
  • Beck, Kent; Andres, Cynthia (2004): Extreme Programming Explained. Embrace Change, Addison-Wesley, Boston
  • Beck, Kent (2007): Implementation Patterns, Addison-Wesley, Upper Saddle River, NJ
  • Buschmann, Frank; Meunier, Regine; Rohnert, Hans; Sommerlad, Peter; Stal, Michael (1996): Pattern-Oriented Software Architecture. Volume 1: A System of Patterns, John Wiley & Sons, Chichester
  • Evans, Eric (2004): Domain-Driven Design, Addison Wesley, Boston
  • Fowler, Martin (1999): Refactoring. Improving the Design of Existing Code, Addison-Wesley Longman, Boston
  • Fowler, Martin (2003): Patterns of Enterprise Application Architecture, Addison Wesley, Boston
  • Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1995): Design Patterns. Elements of Reusable Object-Oriented Software, Addison-Wesley, Boston
  • Kerievsky, Joshua (2005): Refactoring to Patterns, Addison-Wesley, Boston
  • Larman, Craig (2005): Applying UML and Patterns, Prentice Hall, Upper Saddle River, New Jersey
  • Meszaros, Gerard (2007): xUnit Test Patterns, Addison-Wesley, Boston
de/lehre/softwareentwicklung/buch/17/index.txt · Zuletzt geändert: von 127.0.0.1