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äufig auftretende Probleme im Softwaredesign. Sie sind kein Code, den man direkt kopiert – sie sind Vorlagen oder Blaupausen, die beschreiben, wie Klassen und Objekte strukturiert werden sollten, um spezifische Herausforderungen elegant zu lösen.
Das Konzept wurde durch die „Gang of Four“ (GoF) in ihrem Buch von 1994 bekannt gemacht, das 23 grundlegende Muster katalogisierte. Diese Muster werden normalerweise in drei Kategorien unterteilt:
| Kategorie | Zweck | Beispiele |
|---|---|---|
| Erzeugungsmuster | Mechanismen zur Objekterzeugung | Singleton, Factory, Builder |
| Strukturmuster | Zusammensetzung von Klassen und Objekten | Adapter, Decorator, Composite |
| Verhaltensmuster | Interaktion und Verantwortlichkeit von Objekten | Observer, Strategy, Command |
Warum sollte man Design Patterns lernen? Sie bieten ein gemeinsames Vokabular unter Entwicklern – zu sagen „verwende hier eine Factory“ kommuniziert sofort eine komplexe Idee. Sie helfen Ihnen auch dabei, Lösungen nicht neu erfinden zu müssen, und machen Ihren Code flexibler und wartbarer.
In C++ nutzen Design Patterns die OOP-Funktionen, die Sie bereits gelernt haben: Vererbung, Polymorphismus, abstrakte Klassen und Templates. In den nächsten Lektionen werden Sie mehrere wesentliche Muster implementieren und verstehen, wann jedes einzelne das richtige Werkzeug für die jeweilige Aufgabe ist.
Aufgabe
EinfachLassen Sie uns einen einfachen Muster-Klassifizierer erstellen, der Ihr Verständnis der drei Entwurfsmuster-Kategorien demonstriert. Sie werden ein System erstellen, das einen Musternamen entgegennimmt und identifiziert, zu welcher Kategorie er gehört – Creational, Structural oder Behavioral – zusammen mit einer kurzen Beschreibung des Zwecks dieser Kategorie.
Sie werden Ihren Code über drei Dateien organisieren:
PatternCategory.h: Definieren Sie eine abstrakte Basisklasse namensPatternCategory, die eine Entwurfsmuster-Kategorie repräsentiert. Sie sollte Folgendes haben:- Eine rein virtuelle Methode
getName(), die den Kategorienamen als String zurückgibt - Eine rein virtuelle Methode
getPurpose(), die eine Beschreibung dessen zurückgibt, was Muster in dieser Kategorie tun - Einen virtuellen Destruktor
Erstellen Sie dann drei abgeleitete Klassen, die von
PatternCategoryerben:CreationalCategory— gibt den Namen"Creational"und den Zweck"Object creation mechanisms"zurückStructuralCategory— gibt den Namen"Structural"und den Zweck"Class and object composition"zurückBehavioralCategory— gibt den Namen"Behavioral"und den Zweck"Object interaction and responsibility"zurück
- Eine rein virtuelle Methode
PatternClassifier.h: Erstellen Sie eine KlassePatternClassifier, die identifizieren kann, zu welcher Kategorie ein gegebenes Muster gehört.Ihr Klassifizierer sollte eine Methode
classifyhaben, die einen Musternamen (String) entgegennimmt und einen Pointer auf die entsprechendePatternCategoryzurückgibt. Verwenden Sie Smart Pointer (std::unique_ptr) für die 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, geben Sie
nullptrzurück.- Creational:
main.cpp: Lesen Sie eine einzelne Eingabe ein – den Namen eines Entwurfsmusters.Erstellen Sie einen
PatternClassifierund verwenden Sie ihn, um das eingegebene Muster zu klassifizieren. Wenn das Muster erkannt wird, geben Sie Folgendes aus:[PatternName] is a [CategoryName] pattern Purpose: [CategoryPurpose]Wenn das Muster nicht erkannt wird, geben Sie 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, während Sie Vererbung, Polymorphismus und Smart Pointer üben – alles Konzepte, die Sie bereits beherrschen. Die Struktur mit mehreren Dateien spiegelt wider, wie reale Projekte verwandte Klassen organisieren.
Spickzettel
Design-Patterns (Entwurfsmuster) sind wiederverwendbare Lösungen für häufig auftretende Probleme im Softwaredesign. Sie dienen als Vorlagen für die Strukturierung von Klassen und Objekten, nicht als direkt kopierbarer Code.
Design-Patterns werden in drei Hauptkategorien unterteilt:
| Kategorie | Zweck | Beispiele |
|---|---|---|
| Erzeugungsmuster (Creational) | Mechanismen zur Objekterzeugung | Singleton, Factory, Builder |
| Strukturmuster (Structural) | Zusammensetzung von Klassen und Objekten | Adapter, Decorator, Composite |
| Verhaltensmuster (Behavioral) | Interaktion und Verantwortlichkeit von Objekten | Observer, Strategy, Command |
Vorteile von Design-Patterns:
- Bieten ein gemeinsames Vokabular für Entwickler
- Vermeiden das Neuerfinden von Lösungen für gängige Probleme
- Machen Code flexibler und wartbarer
In C++ nutzen Design-Patterns OOP-Funktionen wie Vererbung, Polymorphie, abstrakte Klassen und Templates.
Probier es selbst
#include <iostream>
#include <string>
#include "PatternClassifier.h"
int main() {
// Lies den Musternamen 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 & QuelldateienNamensräume & GültigkeitsbereicheEinführung in OOP in C++Klassen vs. ObjekteDer 'this'-PointerMethoden (Elementfunktionen)Attribute (Datenelemente)Grundlagen zu Ctors & DtorsRückblick - Einfacher Taschenrechner4Klasseneigenschaften
Instanz- vs. statische MemberGetter und SetterConst-MemberfunktionenMutable-SchlüsselwortStatische Methoden und VariablenFriend-Funktionen & KlassenZusammenfassung - Bankkonto-Manager7Vererbung
Grundlagen der VererbungZugriffsstufen bei VererbungAufrufreihenfolge von Ctor & DtorÜberschreiben von MethodenVirtuelle Funktionen & VTableMehrfachvererbungVirtuelle VererbungRückblick - Mitarbeiter-Hierarchie10STL-Übersicht
STL-Übersicht & PhilosophieSTL-ContainerIteratorenSTL-AlgorithmenFunktoren & Lambda-AusdrückeRückblick – Wortfrequenz13Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory & Abstrakte FabrikBuilder-MusterObserver-MusterStrategy-Muster2Speicherverwaltung
Stack vs. Heap SpeicherZeiger und ReferenzenDynamischer Speicher (new/delete)Smart Pointers in C++RAII in C++Rückblick – Dynamischer Array-Manager5Kapselung
Zugriffsspezifizierer in C++Zugriffsspezifizierer im DetailInformation HidingStruct vs. ClassVerschachtelte & innere KlassenRückblick - Studentenverwaltungssystem8Polymorphie
Kompilierzeit- vs. Laufzeit-PolymorphieFunktionsüberladungVirtuelle Funktionen – WiederholungRein virtuelle FunktionenAbstrakte KlassenInterface-Design in C++Dynamic Casting & RTTIZusammenfassung – Formen-Rechner3Konstruktoren & Destruktoren
StandardkonstruktorParametrisierter KonstruktorKopierkonstruktorVerschiebekonstruktorKonstruktor-InitialisierungslistenDelegierende KonstruktorenDestruktoren im DetailRule of Three / Five / ZeroZusammenfassung - String-Klasse6Operatorüberladung
Einführung in die OperatorüberladungArithmetische OperatorüberladungVergleichsoperatorüberladungStream-OperatorenZuweisungsoperatorüberladungÜberladen der [] und () OperatorenTypumwandlungsoperatorenRückblick - Matrix-Klasse9Templates
FunktionstemplatesKlassentemplatesTemplate-SpezialisierungVariadische TemplatesSFINAE & Type Traits GrundlagenRückblick - Generische Container