Einführung in Entwurfsmuster
Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy. Lektion 90 von 104.
Entwurfsmuster sind bewährte, wiederverwendbare Lösungen für häufige Probleme, die beim Softwareentwurf auftreten. Es ist kein Code, den du direkt kopierst – sie sind Vorlagen oder Baupläne, die beschreiben, wie Klassen und Objekte strukturiert werden, um bestimmte Herausforderungen elegant zu lösen.
Das Konzept wurde durch die „Gang of Four“ (GoF) in ihrem 1994 erschienenen Buch populär gemacht, in dem 23 grundlegende Muster katalogisiert wurden. Diese Muster werden üblicherweise in drei Kategorien eingeteilt:
| Kategorie | Zweck | Beispiele |
|---|---|---|
| Erzeugungsmuster | Mechanismen zur Objekterzeugung | Singleton, Factory, Builder |
| Strukturmuster | Zusammensetzung von Klassen und Objekten | Adapter, Decorator, Composite |
| Verhaltensmuster | Interaktion und Zuständigkeit von Objekten | Observer, Strategy, Command |
Warum solltest du Entwurfsmuster lernen? Sie schaffen ein gemeinsames Vokabular unter Entwicklern – die Aussage „Verwende hier eine Factory“ vermittelt sofort eine komplexe Idee. Außerdem helfen sie dir, das Rad nicht neu zu erfinden, und machen deinen Code flexibler und einfacher zu warten.
In C++ nutzen Entwurfsmuster die OOP-Funktionen, die du bereits kennengelernt hast: Vererbung, Polymorphismus, abstrakte Klassen und Templates. In den nächsten Lektionen wirst du mehrere grundlegende Muster implementieren und verstehen, wann welches Muster das richtige Werkzeug ist.
Aufgabe
EinfachErstellen wir einen einfachen Musterklassifizierer, der dein Verständnis der drei Entwurfsmusterkategorien demonstriert. Du erstellst ein System, das einen Musternamen entgegennimmt und bestimmt, zu welcher Kategorie er gehört: Creational, Structural oder Behavioral. Dazu kommt eine kurze Beschreibung des Zwecks dieser Kategorie.
Du organisierst deinen Code auf drei Dateien:
PatternCategory.h: Definiere eine abstrakte Basisklasse namensPatternCategory, die eine Entwurfsmusterkategorie repräsentiert. Sie sollte Folgendes haben:- Eine rein virtuelle Methode
getName(), die den Kategorienamen als Zeichenfolge zurückgibt - Eine rein virtuelle Methode
getPurpose(), die eine Beschreibung dessen zurückgibt, was Muster dieser Kategorie bewirken - Einen virtuellen Destruktor
Erstelle anschließend drei abgeleitete Klassen, die von
PatternCategoryerben:CreationalCategory: Gibt als Namen"Creational"und als Zweck"Object creation mechanisms"zurückStructuralCategory: Gibt als Namen"Structural"und als Zweck"Class and object composition"zurückBehavioralCategory: Gibt als Namen"Behavioral"und als Zweck"Object interaction and responsibility"zurück
- Eine rein virtuelle Methode
PatternClassifier.h: Erstelle eine KlassePatternClassifier, die bestimmen kann, zu welcher Kategorie ein bestimmtes Muster gehört.Dein Klassifizierer sollte eine Methode
classifybesitzen, die einen Musternamen (Zeichenfolge) entgegennimmt und einen Zeiger auf die passendePatternCategoryzurückgibt. Verwende Smart Pointer (std::unique_ptr) zur Speicherverwaltung.Der Klassifizierer sollte diese Muster erkennen:
- Creational:
Singleton,Factory,Builder - Structural:
Adapter,Decorator,Composite - Behavioral:
Observer,Strategy,Command
Wenn der Mustername nicht erkannt wird, gib
nullptrzurück.- Creational:
main.cpp: Lies eine einzelne Eingabe ein: den Namen eines Entwurfsmusters.Erstelle einen
PatternClassifierund verwende ihn, um das eingegebene Muster zu klassifizieren. Wenn das Muster erkannt wird, gib Folgendes aus:[PatternName] is a [CategoryName] pattern Purpose: [CategoryPurpose]Wenn das Muster nicht erkannt wird, gib Folgendes aus:
Unknown pattern: [PatternName]
Zum Beispiel bei der Eingabe Singleton:
Singleton is a Creational pattern
Purpose: Object creation mechanismsBei der Eingabe Observer:
Observer is a Behavioral pattern
Purpose: Object interaction and responsibilityBei der Eingabe Proxy:
Unknown pattern: ProxyDiese Herausforderung festigt die drei Kategorien von Entwurfsmustern und bietet zugleich Übung mit Vererbung, Polymorphie und Smart Pointern: alles Konzepte, die du bereits beherrschst. Die Struktur mit mehreren Dateien spiegelt wider, wie in realen Projekten zusammengehörige Klassen organisiert werden.
Probier es selbst
#include <iostream>
#include <string>
#include "PatternClassifier.h"
int main() {
// Lies den Namen des Musters ein
std::string patternName;
std::cin >> patternName;
// TODO: Erstelle eine PatternClassifier-Instanz
// TODO: Verwende den Klassifikator, um das Eingabemuster zu klassifizieren
// TODO: Wenn das Muster erkannt wird, gib Folgendes aus:
// "[PatternName] is a [CategoryName] pattern"
// "Purpose: [CategoryPurpose]"
// TODO: Wenn das Muster nicht erkannt wird (nullptr), gib Folgendes aus:
// "Unknown pattern: [PatternName]"
return 0;
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienC++ Build & KompilierungHeader-Dateien & QuelldateienNamespaces & GültigkeitsbereichEinführung in OOP mit C++Klassen vs. ObjekteDer „this“-ZeigerMethoden (Member-Funktionen)Attribute (Datenmember)Grundlagen zu Ctors & DtorsRückblick – Einfacher Taschenrechner4Klassenattribute
Instanz- vs. statische MemberGetter und SetterConst-MemberfunktionenMutable-SchlüsselwortStatische Methoden und VariablenFriend-Funktionen und -KlassenZusammenfassung – Bankkontoverwaltung7Vererbung
Grundlagen der VererbungZugriffsebenen bei der VererbungAufrufreihenfolge von Ctor & DtorÜberschreiben von MethodenVirtuelle Funktionen & VTableMehrfachvererbungVirtuelle VererbungRückblick – Mitarbeiterhierarchie10STL-Übersicht
STL-Übersicht & PhilosophieSTL-ContainerIteratorenSTL-AlgorithmenFunktoren & Lambda-AusdrückeRückblick – Worthäufigkeit13Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory und Abstract FactoryBuilder-MusterBeobachter-MusterStrategie-Muster2Speicherverwaltung
Stack- vs. Heap-SpeicherZeiger und ReferenzenDynamischer Speicher (new/delete)Intelligente Zeiger in C++RAII in C++Rückblick – Dynamischer Array-Manager5Kapselung
Zugriffsbezeichner in C++Zugriffsbezeichner im DetailInformationsverbergungStruct vs. KlasseVerschachtelte und innere KlassenWiederholung – Studierendenverwaltungssystem8Polymorphie
Polymorphie zur Compilezeit vs. LaufzeitFunktionsüberladungVirtuelle Funktionen erneut betrachtetRein virtuelle FunktionenAbstrakte KlassenInterface-Design in C++Dynamic Casting & RTTIRückblick – Shape-Calculator3Konstruktoren & Destruktoren
StandardkonstruktorParametrisierter KonstruktorKopierkonstruktorMove-KonstruktorKonstruktor-InitialisierungslistenDelegierende KonstruktorenDestruktor im DetailDrei-/Fünf-/Null-RegelZusammenfassung – String-Klasse6Operatorüberladung
Einführung in die OperatorüberladungArithmetische OperatorüberladungVergleichsoperatorüberladungStream-OperatorenZuweisungsoperatorüberladungÜberladung der Operatoren [] und ()TypkonvertierungsoperatorenWiederholung – Matrix-Klasse9Templates
FunktionstemplatesKlassen-TemplatesTemplate-SpezialisierungVariadische TemplatesGrundlagen zu SFINAE und Type TraitsRückblick – Generischer ContainerÜbe selbstständig: Online-C++-Compiler