Benutzer-Werkzeuge

Webseiten-Werkzeuge


de:lehre:programmierkonzepte:ss2020: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
Folien
PDF
Glossar
PDF
Video
MP4


Webcast

Hinweis: Der Webcast wurde mit Tiny Webcasts for Lecture(r)s erstellt.

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.

Fragen zur Vertiefung und Wiederholung

Diese Fragen dienen der persönlichen Beschäftigung mit der Thematik, werden aber nicht separat in der Vorlesung besprochen.

  • 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 der Vorlesung 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/programmierkonzepte/ss2020/17/index.txt · Zuletzt geändert: 2020/09/30 21:35 von 127.0.0.1