München, 29.11.2011: Florian Schinagl über Softwarewartung mit dem Decorator Pattern
Die Softwarewartung gehört bei uns zum Alltag. Selten können wir auf der grünen Wiese neue Software entwickeln. Zum Refactoring von bestehender Software gibt es viele Bücher (z.B. Refactoring). Dabei werden altbewährte Praktiken beschrieben, um mit bestimmten Problemen umzugehen.
Aber wo fängt man bei komplexen Softwaresystemen an zum Refaktorisieren? Gerade bei Software, bei der unterschiedliche Entwickler über die Jahre mitgewirkt haben, gibt es selten noch jemanden, der alle Komponenten kennt bzw. versteht. Oft bietet das Projekt nur wenig Zeit für die Implementierung neuer Features. Da stellt sich die Frage, wie man bestehenden Softwarekomponenten Funktionalität ohne Seiteneffekte hinzufügen kann. Ich hatte letztens eine angeregte Diskussion mit Kollegen über dieses Thema, speziell über den Einsatz des Decorator Pattern bzw. seine Tauglichkeit in diesem Fall.
Decorator Pattern
Ein Decorator fügt Funktionalität zu einer Klasse hinzu, ohne die dekorierte Klasse ändern zu müssen. Dazu implementiert der Decorator dasselbe Interface wie die dekorierte Klasse. Zur Laufzeit leitet der Decorator Methodenaufrufe an das dekorierte Objekt weiter und hat zusätzlich die Möglichkeit, Funktionalität hinzuzufügen.
Ein einfaches Beispiel:
Der Decorator LoggedFoo erweitert ein beliebiges IFoo um einen Log-Aufruf, ohne dass das dekorierte Objekt Kenntnis hat bzw. haben muss.
Bemerkung: Natürlich ist dies ein sehr einfaches Beispiel für einen Decorator. Um einen solchen Log-Mechanismus nicht umständlich für jedes Interface implementieren zu müssen, kann man sich heute anderer Techniken bedienen, wie z.B. Aspect Oriented Programming (AOP), Dynamic Proxies oder Runtime Code Generation.
Mit dem Decorator Pattern lässt sich also auf einfache Art und Weise ein bestehendes Objekt zur Laufzeit um Funktionalität erweitern. Mit verschiedenen Decorators ist man auch in der Lage, Funktionalitäten zu kombinieren. Dazu werden verschiedene Decorator-Objekte verschachtelt. Das von den Decorator-Objekten gehüllte Ursprungsobjekt bleibt dabei immer unangetastet.
Clean Code
Der richtige Einsatz des Decorator-Pattern fördert Verständlichkeit und Erweiterbarkeit. In einem Legacy-System kann man daraus zumindest punktuell und inkrementell Nutzen ziehen. Folgende Clean Code Prinzipien sind unmittelbar erfüllt:
- Open-Closed Principle: einer Klasse wird durch einen Decorator Funktionalität hinzugefügt, ohne sie zu verändern.
- Separation of Concerns: das vom Decorator implementierte Belang hat selten direkten Bezug zur dekorierten Klasse (siehe Beispiel: Logging). Der Decorator separiert diese Funktionalität in eine eigene Klasse.
- Single Responsibility Principle: der Decorator hat eine und nur eine klar abgegrenzte Verantowrtlichkeit (siehe Beispiel: Logging)
Neue Features durch Dekoration
Was erreiche ich damit?
- Bestehende Komponenten können unangetastet bleiben (Vermeidung von Seiteneffekten, OCP)
- Unmittelbare Erfüllung grundlegender Clean Code Prinzipien
- Die Erweiterung ist selbst bei unüberschaubaren, evolutionär entstandenen (Monster-)Klassen ohne größeres Risiko möglich
- Der Decorator kann für sich allein gut getestet werden
- Man ist (optimalerweise) schneller
- Etablierung von Standard-Patterns trägt zu einem Team-Vokabular bei, das wenig Spielraum für Interpretation lässt
Wo sind die Grenzen?
- Der Decorator muss weiterhin den Vertrag des implementierten Interfaces erfüllen (z.B. Ein-/Ausgabeparameter, Performance, Invarianten)
- Der Decorator darf keine internen Informationen aus der dekorierten Klasse benötigen (die public-sichtbaren Informationen müssen ausreichen)
Ein Decorator ist sicher nicht das Allheilmittel für alle Probleme der Softwarewartung. Es gibt durchaus Aufgaben, bei denen der Einsatz eines Decorators nicht praktikabel ist. Aber in einigen Fällen ermöglicht er es dem Entwickler, Features hinzuzufügen und durch isolierten Test des Decorators die Risiken gering zu halten.
Hinterlassen Sie einen Kommentar
Sie müssen angemeldet sein, um einen Kommentar zu hinterlassen.