Design-Patterns sind Lösungen für wiederkehrende Probleme beim Softwaredesign, die in der realen Anwendungsentwicklung immer wieder auftreten. Sie beschreiben wiederverwendbare Entwürfe und Interaktionen zwischen Objekten. Einige sind sehr verbreitet, etwa Singleton, Factory und Strategy; andere, wie das Flyweight-Pattern, werden deutlich seltener eingesetzt.
Manchmal implementieren Entwickler Patterns unzureichend. Dadurch können Designprobleme entstehen und die eigentlichen Vorteile der Patterns verloren gehen. Deshalb ist es sinnvoll, schlecht implementierte Patterns zu erkennen und ihre Umsetzung zu korrigieren.
Um solche Probleme zu erkennen, benötigen wir möglichst viele Informationen über den Quellcode, darunter:
- Eigenschaften von Klassen, Methoden und Feldern.
- Vererbungsbeziehungen zwischen Klassen.
- Abhängigkeiten zwischen Klassen, Methoden und Feldern.
- Stellen, an denen Klassen instanziiert werden.
erzeugt ein Codemodell, das all diese Daten enthält und Abfragen mit CQLinq. Let’s try to detect the misuse of two patterns: Singleton and Strategy.
Singleton
Das Singleton-Pattern ist ein Design-Pattern, das die Instanziierung einer Klasse auf ein einziges Objekt beschränkt. Seine Verwendung ist jedoch umstritten, und nicht alle Architekten und Designer empfehlen es; hier finden Sie einen Artikel über die Singleton-Kontroverse.
Ein häufiger Fehler bei der Implementierung des Singleton-Patterns besteht darin, den Konstruktor nicht als privat zu deklarieren.
Die folgende Abfrage erkennt alle Klassen mit den typischen Merkmalen eines Singletons – also Klassen mit einem statischen Feld, das auf den eigenen Typ verweist, sowie einer statischen Methode, die dieses Feld zurückgibt –, jedoch ohne privaten Konstruktor.

Strategy
Es gibt viele Situationen, in denen sich Klassen lediglich in ihrem Verhalten unterscheiden. In diesem Fall ist es sinnvoll, die Algorithmen in separate Klassen auszulagern, sodass zur Laufzeit unterschiedliche Algorithmen ausgewählt werden können. Das Strategy-Pattern eignet sich dafür besonders gut.
Hier ist das UML-Diagramm dieses Patterns:

Wie das Diagramm zeigt, verwendet die Context-Klasse die abstrakte Klasse „Strategy“ und kennt die konkreten Implementierungen nicht. In manchen Implementierungen greift die Context-Klasse jedoch direkt auf konkrete Klassen zu. Hier ist ein Beispiel für diesen Fehler:

Suchen wir mit CQLinq nach allen Klassen, die dieses Strategy-Pattern verwenden. Dazu können wir nach abstrakten Klassen mit mehreren abgeleiteten Klassen suchen, bei denen der Client Methoden der konkreten Implementierungen direkt verwendet, anstatt über die abstrakte Klasse zu arbeiten.

Das Ergebnis dieser Abfrage zeigt die abgeleiteten Typen, die von anderen Methoden direkt anstelle der abstrakten Typen verwendet werden. Anschließend müssen lediglich die betreffenden Methoden ermittelt werden, um festzustellen, an welchen Stellen die Implementierung des Strategy-Patterns korrigiert werden sollte.
Damit werden allerdings nicht exakt die Stellen identifiziert, an denen das Strategy-Pattern schlecht implementiert ist. Stattdessen werden potenzielle Problembereiche hervorgehoben, die ein Entwickler anschließend manuell prüfen kann.
Fazit
Design-Patterns können die Qualität eines Softwaredesigns verbessern. Werden sie jedoch schlecht implementiert, können sie selbst zur Quelle von Problemen und Fehlern werden.
