
UML-Muster suche: Automatisierung mit Together
Dokumentinformationen
Autor | Véronique Spranger |
Schule | Technische Universität Ilmenau |
Fachrichtung | Informatik und Automatisierung |
Dokumenttyp | Studienarbeit |
Sprache | German |
Format | |
Größe | 150.12 KB |
Zusammenfassung
I.Automatische Erkennung von Entwurfsmustern in UML Diagrammen
Diese Arbeit befasst sich mit der automatischen Suche von Entwurfsmustern (Design Patterns) in UML-Diagrammen. Das Hauptproblem ist die mühsame und fehleranfällige manuelle Extraktion von Informationen aus dem Quellcode. Die Lösung liegt in der Entwicklung eines Moduls, das mit Hilfe des Reverse Engineering aus dem Quellcode ein UML-Modell erstellt und dann mithilfe von Algorithmen spezifische Entwurfsmuster, wie z.B. Kompositum und Besucher, identifiziert. Das Modul wird in Together 6.0.1 implementiert und nutzt dessen Open API für den Zugriff auf Modellinformationen und Quellcode (Java, C++). Der Ansatz basiert auf der Arbeit von Naumann [Naum 01], der Merkmale für die Identifizierung von Entwurfsmustern in UML-Modellen definiert hat.
1. Problematik der manuellen Entwurfsmuster Erkennung
Die manuelle Extraktion von Entwurfsmustern aus dem Quellcode von Softwaresystemen ist aufwendig, fehleranfällig und zeitintensiv. Das erschwert das Verständnis bestehender Systeme und die sichere Durchführung von Änderungen. Oftmals fehlen die notwendigen Dokumentationen, die Aufschluss über die verwendeten Entwurfsmuster geben würden. Die Folge sind mühsame Analysen des Quellcodes, die zu unvollständigem Verständnis und unerwünschten Seiteneffekten bei Modifikationen führen können. Die vorliegende Arbeit zielt daher darauf ab, diesen Prozess durch die Entwicklung eines automatisierten Systems zur Mustererkennung zu verbessern. Die automatisierte Findung von Entwurfsmustern setzt deren präzise Beschreibung und Charakterisierung voraus, um eine zuverlässige Identifizierung zu gewährleisten. Die Grundlage dieser Arbeit bildet der Ansatz von Naumann [Naum 01], der sich mit der Erkennung von Mustern in UML-Modellen befasst und Merkmale definiert, die auf das Vorhandensein eines Musters hinweisen, sowie Merkmale, die dessen Abwesenheit signalisieren, um Fehlklassifizierungen zu minimieren. Die Arbeit betont die Notwendigkeit einer automatisierten Lösung, um die Effizienz und Zuverlässigkeit der Softwareanalyse deutlich zu steigern.
2. Reverse Engineering und UML Modellierung
Da die benötigten Informationen über die verwendeten Entwurfsmuster oft in der Dokumentation fehlen, ist Reverse Engineering notwendig, um aus dem Quellcode des Softwaresystems die notwendigen Informationen zu extrahieren. Reverse Engineering wird hier als der Prozess der Extraktion und Repräsentation von Informationen aus einem Softwaresystem in einer anderen Form oder auf einem höheren Abstraktionsniveau definiert ([Mül97]). Das Ziel ist die Generierung eines UML-Modells aus dem Quellcode, welches dann als Grundlage für die automatisierte Erkennung der Entwurfsmuster dient. Die Arbeit betont, dass die meisten Softwaresysteme heute nicht komplett neu entwickelt werden, sondern auf bestehenden Systemen basieren und angepasst werden ([Balzert98]). Ein tiefes Verständnis des Systems ist daher unabdingbar für die sichere Durchführung von Änderungen und Weiterentwicklungen. Fehlende Dokumentation und die Nichtverfügbarkeit der Entwickler erschweren dieses Verständnis zusätzlich. Daher ist die Entwicklung eines Werkzeugs, welches das Reverse Engineering automatisiert und die Extraktion relevanter Informationen vereinfacht, entscheidend für eine effiziente und sichere Softwareentwicklung. Der Prozess des Reverse Engineerings wird für die erfolgreiche Umsetzung des Projekts als zentraler Baustein angesehen.
3. Integration in Together 6.0.1 und die Open API
Um die automatische Erkennung von Entwurfsmustern zu realisieren, wird ein Modul entwickelt, das in die Software Together 6.0.1 integriert wird. Together 6.0.1 bietet eine Open API, die die Erweiterung der Software durch eigene Module ermöglicht. Die Arbeit beschreibt die Funktionalitäten von Together 6.0.1, die für die Entwicklung des Moduls relevant sind, insbesondere die Open API mit ihren verschiedenen Interfaces. Dabei wird die IDE (ein read-only Interface für den Zugriff auf Modellinformationen), das Read-Write Interface (RWI) zum Ändern des Modells und das Source Code Interface (SCI) zum Zugriff auf den Quellcode des Projekts detailliert beschrieben. Die Arbeit hebt die Herausforderungen hervor, die sich aus der unzureichenden Dokumentation der API ergeben. Das Entwickeln des Moduls erfordert ein tiefes Verständnis der API und ihrer verschiedenen Interfaces. Um die Funktionalität zu erweitern, muss das Modul die Together Open API effektiv nutzen und sowohl auf das UML-Modell als auch auf den zugrundeliegenden Quellcode zugreifen können. Die Wahl von Together 6.0.1 als Plattform begründet sich in dessen Eigenschaften als umfassende Entwicklungsumgebung mit integrierter UML-Modellierung und der Möglichkeit der Erweiterung durch eigene Module.
II.Charakterisierung und Implementierung der Entwurfsmuster
Die Arbeit konzentriert sich auf die Implementierung von Algorithmen zur Erkennung ausgewählter Entwurfsmuster aus [Gamma+96]. Diese Muster werden anhand ihrer Struktur und ihres Zwecks charakterisiert. Der Fokus liegt dabei auf der automatisierten Erzeugung der Musterstruktur mit Together 6.0.1 und der Identifizierung charakteristischer Merkmale im UML-Modell, die auf das Vorhandensein eines bestimmten Entwurfsmusters hinweisen. Die Algorithmen berücksichtigen sowohl klassenbasierte als auch objektbasierte Strukturmuster und Verhaltensmuster.
1. Beschreibung und Charakterisierung der Entwurfsmuster
Dieser Abschnitt beschreibt die ausgewählten Entwurfsmuster, die im Rahmen der Arbeit implementiert und untersucht werden. Die Grundlage bildet das Buch "Design Patterns" [Gamma+96], aus dem die Muster entnommen werden. Es werden elf der dreiundzwanzig Muster aus diesem Buch ausgewählt, deren Struktur mit der Software Together 6.0.1 automatisch erzeugt werden kann. Für die restlichen Muster wird die in [Gamma+96] verwendete OMT-Notation herangezogen. Jedes ausgewählte Muster wird detailliert beschrieben, inklusive seines Zwecks und einer kurzen Erklärung seiner Funktionsweise. Die Struktur der Muster wird, sofern möglich, mit UML-Diagrammen aus Together 6.0.1 dargestellt. Die Beschreibungen basieren auf den Angaben in [Gamma+96]. Entwurfsmuster werden dabei nach dem in [Gamma+96] definierten Schema beschrieben: Mustername, Problembeschreibung (Wann ist das Muster anzuwenden, welches Problem wird adressiert, Kontext), Lösung und Konsequenzen. Die Unterscheidung zwischen klassenbasierten und objektbasierten Strukturmustern wird erläutert, wobei die Flexibilität objektbasierter Muster durch die Möglichkeit der Laufzeitänderung des Kompositionsgefüges hervorgehoben wird. Verhaltensmuster werden als Muster beschrieben, die sich mit Algorithmen und der Zuweisung von Verantwortlichkeiten an Objekte befassen und die Interaktionen zwischen Objekten und Klassen abbilden. Die detaillierte Beschreibung der ausgewählten Entwurfsmuster legt den Grundstein für die spätere Implementierung der Erkennungsalgorithmen.
2. Implementierung der Algorithmen zur Mustersuche
Dieser Abschnitt befasst sich mit der Implementierung der Algorithmen zur automatischen Erkennung der ausgewählten Entwurfsmuster. Die Arbeit beschreibt nicht detailliert jeden Algorithmus, konzentriert sich aber auf die wichtigsten Aspekte der Implementierung und die Herausforderungen. Es wird erwähnt, dass für jedes Suchverfahren eine spezielle Implementierung notwendig war und es nur wenige Methoden gibt, die für mehrere Muster verwendet werden können. Die Implementierung konzentriert sich auf die Analyse von UML-Diagrammen, die durch Reverse Engineering aus dem Quellcode generiert werden. Die Algorithmen überprüfen spezifische Strukturelemente und Beziehungen im UML-Modell, um das Vorhandensein eines bestimmten Entwurfsmusters zu identifizieren. Es werden Methoden vorgestellt, die beispielsweise Subklassen ermitteln (getSubClasses
), implementierte Klassen finden (getImplementedClassesFromModel
) oder Aggregationen mit einer spezifischen Kardinalität (1..*
) identifizieren. Die detaillierte Implementierung der Algorithmen ist im Text nicht vollständig offengelegt; der Fokus liegt auf der Beschreibung der zentralen Konzepte und der Vorgehensweise. Die verwendeten Methoden zeigen den Umgang mit dem UML-Modell und dem Zugriff auf die notwendigen Informationen im Kontext der Together 6.0.1 API. Die Implementierung spiegelt die Komplexität der Mustererkennung wider und betont die Notwendigkeit spezifischer Algorithmen für jedes einzelne Muster.
3. Test und Bewertung der Implementierung
Die entwickelten Algorithmen zur Entwurfsmustererkennung werden an verschiedenen Beispielprojekten getestet. Die Ergebnisse zeigen eine unterschiedliche Performance je nach Programmiersprache (C++ und Java). Im Text wird ein konkretes Beispiel mit dem "Kompositum"-Muster erwähnt, bei dem Probleme mit der Aggregation von Kardinalität 0..* auftraten. Die Änderung der Kardinalität auf 1..* war notwendig, um die korrekte Erkennung zu gewährleisten. Bei einem anderen Projekt (MySQL++) wurden keine Muster gefunden, obwohl die Bedingungen teilweise erfüllt schienen. Ein weiteres Beispielprojekt zeigt Schwierigkeiten im Reverse Engineering von C++ Projekten, da Together nur die Header-Dateien verarbeitete, nicht aber die inkludierten Header-Dateien. Dadurch war manuelles Eingreifen nötig, was den Aufwand deutlich erhöhte. Die Bewertung der Algorithmen hinsichtlich Präzision und Recall ist erschwert, da keine vollständige Dokumentation der Testprojekte mit den tatsächlich implementierten Mustern vorliegt. Die Schwierigkeiten bei der Erkennung von 1..* Aggregationen in unterschiedlichen Programmiersprachen werden ebenfalls diskutiert, wobei auf den Aufwand bei der Erkennung solcher Beziehungen in Java und C++ hingewiesen wird. Die Testphase und die daraus resultierenden Beobachtungen unterstreichen sowohl die Stärken als auch die Limitationen der entwickelten Algorithmen.
III.
Die Entwicklung des Moduls zur automatischen Mustersuche erfolgt als Erweiterung von Together 6.0.1. Die Arbeit beschreibt die Nutzung der Together Open API, insbesondere des Read-Write Interface (RWI) und des Source Code Interface (SCI), um auf Modell- und Quellcodeinformationen zuzugreifen. Die Herausforderungen bei der Nutzung der API werden angesprochen, inklusive der unzureichenden Dokumentation. Das Modul wird als kompiliertes Java-Modul implementiert und über die IDE von Together gesteuert.
1. Together 6.0.1 als Entwicklungsumgebung
Die Arbeit nutzt Together 6.0.1 als Entwicklungsumgebung und Plattform für die Implementierung des Moduls zur automatischen Erkennung von Entwurfsmustern. Together wird nicht nur als Modellierungstool, sondern als komplette Entwicklungsplattform beschrieben, die den gesamten Entwicklungsprozess von der UML-Modellierung über die Implementierung bis zum Deployment unterstützt. Die Software unterstützt mehrere Programmiersprachen, darunter Visual Basic 6 und Visual Basic.Net. Ein zentrales Ziel von Together ist die Vermeidung von Redundanzen zwischen Modell und Implementierung, wobei Sourcecode und Diagramme stets synchronisiert sein sollen. Diese Synchronität soll durch die Übersetzung von Diagramminformationen in Code und umgekehrt gewährleistet werden, was ein echtes Reverse Engineering ermöglicht. Together fungiert als Kommunikationsplattform zwischen verschiedenen Werkzeugen, insbesondere zwischen der Modellierung und der integrierten Entwicklungsumgebung (IDE). Diese Integration vereinfacht den Entwicklungsprozess und ermöglicht einen reibungslosen Datenfluss zwischen den verschiedenen Phasen der Softwareentwicklung. Die Wahl von Together 6.0.1 als Entwicklungsplattform ist von Bedeutung, da es die notwendigen Funktionen für die Modellierung, den Quellcodezugriff und die Erweiterung durch eigene Module bereitstellt.
2. Die Together Open API und ihre Interfaces
Die Erweiterung von Together 6.0.1 erfolgt über die Together Open API, die verschiedene Interfaces zur Verfügung stellt. Die Arbeit beschreibt die wichtigsten Interfaces: die IDE, das Read-Write Interface (RWI) und das Source Code Interface (SCI). Die IDE bietet read-only Zugriff auf das Modell und erlaubt die Extraktion von Informationen, jedoch keine Modifikation. Das RWI erlaubt tiefgreifenden Zugriff auf die Modellarchitektur mit Lese- und Schreibzugriff, ermöglicht somit die Erweiterung der Funktionalität von Together. Das SCI bietet den mächtigsten Zugriff, da es den kompletten Source Code eines Projekts ansprechen und manipulieren kann. Es unterstützt verschiedene Programmiersprachen. Die Arbeit hebt hervor, dass die integrierte API-Dokumentation für neue Nutzer nicht ausreichend detailliert ist, was die Entwicklung des Moduls erschwert. Das Auffinden und richtige Anwenden der benötigten Interfaces ist sehr zeitaufwendig. Die detaillierte Beschreibung dieser Interfaces ist entscheidend für das Verständnis, wie das Modul mit Together interagiert und auf die benötigten Daten zugreift. Die erfolgreiche Integration des Moduls hängt direkt von der korrekten Nutzung der verschiedenen Interfaces der Together Open API ab.
3. Entwicklung und Implementierung des Moduls
Das Modul zur automatischen Mustersuche wird als kompiliertes Java-Modul implementiert, welches das Interface IdeScript
implementiert. Es wird als Nutzer-Modul kategorisiert, d.h. es erscheint im Modulsbaum von Together und kann manuell vom Benutzer ausgeführt werden. Der Modulcode wird im Verzeichnis $THG$\modules\com\together\modules
abgelegt. Der grobe Ablauf des Moduls beinhaltet die Prüfung auf ein aktives Projekt, den Zugriff auf das RWI-Modell und die iterative Verarbeitung aller Pakete und Knoten im Modell. RwiPackage
-Elemente enthalten Modelldaten wie Klassen, Interfaces, Member und Diagramme. Die zentrale Methode Run(IdeContext context)
initiiert den Prozess. Weitere Methoden extrahieren Informationen aus dem Modell und dem Quellcode, z.B. die Ermittlung von Subklassen (getSubClasses
), implementierten Klassen (getImplementedClassesFromModel
) und Aggregationen. Die Arbeit skizziert den grundlegenden Ablauf, beschreibt aber nicht im Detail die Implementierung aller Funktionen. Die Implementierung des Moduls als kompiliertes Java-Modul stellt sicher, dass es mit der Java Virtual Machine von Together kompatibel ist und effizient ausgeführt werden kann. Der Fokus liegt auf der Integration in die bestehende Umgebung und der Nutzung der vorhandenen API-Funktionalitäten.
IV.Implementierte Algorithmen und deren Bewertung
Die Arbeit präsentiert die implementierten Algorithmen zur Erkennung der ausgewählten Entwurfsmuster. Die Algorithmen werden an verschiedenen Beispielprojekten (inkl. einem Beispiel aus [Gamma+96] und MySQL++) getestet. Die Auswertung der Ergebnisse zeigt eine unterschiedliche Performance der Algorithmen abhängig von der verwendeten Programmiersprache (Java, C++). Die Schwierigkeit bei der Bewertung der Präzision und des Recall der Algorithmen liegt im Fehlen einer umfassenden Dokumentation der Testprojekte, welche die tatsächlich vorhandenen Entwurfsmuster auflistet. Die Herausforderungen bei der Erkennung von 1.. Aggregationen* in C++ und Java Projekten werden diskutiert.
1. Algorithmen zur Erkennung von Kompositum und Besucher Muster
Die Arbeit beschreibt die Implementierung von Algorithmen zur automatischen Erkennung von Entwurfsmustern, speziell des Kompositum- und des Besucher-Musters. Die Algorithmen basieren auf der Analyse von UML-Modellen, die durch Reverse Engineering aus dem Quellcode gewonnen werden. Die Erkennung des Kompositum-Musters stützt sich auf die Identifizierung von Aggregationen mit der Kardinalität "1..*" im Modell. Probleme traten bei der Erkennung in C++-Projekten auf, da Together nur die obersten Header-Dateien einbindet und der zusätzliche Aufwand für das manuelle Einbinden der inkludierten Header-Dateien den Reverse-Engineering-Prozess erheblich verlangsamt. Der Algorithmus für das Besucher-Muster analysiert die Methodenaufrufe und Parameter innerhalb der Klassen. Die Erkennung ist in Java-Projekten deutlich einfacher als in C++-Projekten, da in C++ das Klassendiagramm nur die Header-Files abbildet und der Zugriff auf die Implementierung der Methoden in den .cpp-Dateien notwendig ist, um die Parameter zu analysieren und das Vorhandensein des Musters zu überprüfen. Die Implementierung berücksichtigt, dass Methoden des Besucher-Musters mehrere Klassen als Parameter haben können, wobei nur eine dieser Klassen relevant ist für die Erkennung. Für die korrekte Funktionsweise der Algorithmen ist die korrekte Erkennung von Aggregationen mit der Kardinalität 1.. von entscheidender Bedeutung. Die Kompositum-Muster wurden überwiegend nur in mit Together erstellten Projekten gefunden, da hier die Aggregationen durch die Eigenschaft RwiProperty.AGGREGATION zuverlässig erkannt werden konnten.
2. Bewertung der Algorithmen und Herausforderungen
Die Bewertung der implementierten Algorithmen hinsichtlich Präzision und Recall ist schwierig, da für die getesteten Projekte keine Dokumentation existiert, die die tatsächlich implementierten Entwurfsmuster auflistet. Die Ergebnisse zeigen eine deutliche Abhängigkeit der Erkennungsrate von der Programmiersprache. Während das Besucher-Muster in Java-Projekten problemlos erkannt wird, bereitet die Erkennung in C++-Projekten aufgrund der eingeschränkten Sichtbarkeit auf den Quellcode (nur Header-Files) Schwierigkeiten. Ähnliches gilt für das Kompositum-Muster, dessen Erkennung in C++ problematisch ist. Die Erkennung von 1..* Aggregationen stellt sich als besonders herausfordernd dar. In Java müsste ein Attribut getestet werden, das von der Collection-Klasse abgeleitet ist, während in C++ die Suche nach verketteten Listen oder Template-Typen notwendig wäre. Das Vorhandensein von Kommentaren wie "@link aggregation" und "@supplierCardinality 1..*" im Quellcode ist für die Erkennung essentiell, jedoch in existierenden Projekten oft nicht vorhanden. Die Bewertung zeigt die Notwendigkeit weiterer Verbesserungen der Algorithmen, insbesondere für die zuverlässige Erkennung in C++-Projekten und die robuste Handhabung unterschiedlicher Kodierungs-Stile und -Konventionen.
3. Beispielprojekte und deren Ergebnisse
Die Arbeit beschreibt die Ergebnisse der Tests mit verschiedenen Beispielprojekten. Ein in [Gamma+96] beschriebenes Beispielprojekt wurde mit Together umgesetzt und diente als Testfall. Hier wurden sowohl das Kompositum- als auch das Besucher-Muster erfolgreich erkannt, nachdem eine notwendige Anpassung der Kardinalität einer Aggregation vorgenommen wurde. Ein weiteres Projekt, MySQL++, zeigte keine positiven Ergebnisse für die Erkennung der untersuchten Entwurfsmuster. Bei einem weiteren Projekt, erfüllte keine Klasse die Bedingungen für das Besucher-Muster. Die Analyse von Beispielprojekten hat die Stärken und Schwächen der Algorithmen aufgezeigt, wobei die Abhängigkeit der Erkennungsgenauigkeit von der Programmiersprache und der Qualität des Quellcodes deutlich wurde. Die Ergebnisse betonen den Bedarf an weiteren Verbesserungen der Algorithmen und einer robusteren Handhabung von verschiedenen Kodierungs-Stilen und -Konventionen. Der Aufwand des Reverse Engineering in C++ Projekten, verursacht durch die fehlende automatische Einbindung aller Header-Dateien, wird ebenfalls hervorgehoben. Dies zeigt die Notwendigkeit von zukünftigen Verbesserungen im Bereich des automatischen Quellcode-Parsings und der Datenextraktion.
V.Zusammenfassung und Ausblick
Die Arbeit zeigt die Herausforderungen bei der automatisierten Erkennung von Entwurfsmustern in UML-Modellen auf. Die implementierten Algorithmen erfordern eine spezifische Anpassung an die jeweilige Programmiersprache und die Besonderheiten des Reverse Engineering-Prozesses. Die Ergebnisse unterstreichen den Bedarf an verbesserten Methoden zur Erkennung von Entwurfsmustern, insbesondere bei komplexen Softwareprojekten. Zukünftige Arbeiten könnten sich auf die Verbesserung der Algorithmen, die Erweiterung auf weitere Entwurfsmuster und die Verbesserung der Robustheit gegenüber unterschiedlichen Quellcodes konzentrieren.
1. Zusammenfassung der Ergebnisse
Die Arbeit fasst die Ergebnisse der automatisierten Suche nach Entwurfsmustern in UML-Diagrammen zusammen. Die Suche wurde mit Together 6.0.1 durchgeführt und basierte auf der Erweiterung der Software durch ein selbst entwickeltes Modul. Die Algorithmen, die auf dem Ansatz von Naumann [Naum 01] beruhen, mussten erweitert und an die spezifischen Anforderungen angepasst werden. Für jedes untersuchte Entwurfsmuster (z.B. Kompositum, Besucher) wurde eine separate Implementierung benötigt, was den Implementierungsaufwand unterstreicht. Die Tests an verschiedenen Beispielprojekten zeigten eine unterschiedliche Performance der Algorithmen in Abhängigkeit von der Programmiersprache (C++ und Java). Während das Besucher-Muster in Java-Projekten zuverlässig erkannt wurde, traten in C++-Projekten aufgrund des eingeschränkten Zugriffs auf den Quellcode (nur Header-Files) Probleme auf. Auch die Erkennung von 1..* Aggregationen, die für die Identifizierung bestimmter Muster essentiell sind, erwies sich als problematisch. Die fehlende Dokumentation der Testprojekte erschwerte die genaue Bewertung der Algorithmen hinsichtlich Präzision und Recall. Die Zusammenfassung betont die Herausforderungen bei der automatisierten Erkennung von Entwurfsmustern und die Notwendigkeit von weiterführenden Arbeiten.
2. Ausblick auf zukünftige Arbeiten
Die Arbeit schließt mit einem Ausblick auf zukünftige Forschungsarbeiten. Es wird deutlich, dass die automatisierte Suche nach Entwurfsmustern in UML-Modellen mit vielen Herausforderungen verbunden ist. Die implementierten Algorithmen benötigten spezifische Anpassungen für jedes Suchverfahren, und der Implementierungsaufwand wurde als höher eingeschätzt als anfänglich angenommen. Zukünftige Arbeiten könnten sich auf die Verbesserung der bestehenden Algorithmen konzentrieren, um eine höhere Genauigkeit und Robustheit zu erreichen. Die Erweiterung der Algorithmen auf weitere Entwurfsmuster stellt eine weitere sinnvolle Richtung der zukünftigen Forschung dar. Besondere Aufmerksamkeit sollte der Verbesserung der Handhabung von verschiedenen Programmiersprachen und Quellcodestilen gewidmet werden, um die Zuverlässigkeit des Systems zu erhöhen. Die Verbesserung des Reverse-Engineering-Prozesses, insbesondere für C++-Projekte, um einen umfassenderen Zugriff auf den Quellcode zu gewährleisten, ist ebenfalls eine wichtige Aufgabe für zukünftige Forschung. Insgesamt wird die Notwendigkeit weiterer Forschung zur Verbesserung der Methoden und Algorithmen zur automatisierten Erkennung von Entwurfsmustern hervorgehoben.