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.
Diese Fragen dienen der persönlichen Beschäftigung mit der Thematik, es werden aber keine Antworten zur Verfügung gestellt.
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.
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.
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].