Entwurfsmuster in C++ mit Beispielen: vollständige Analyse

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Warum Entwurfsmuster in C++ wichtig sind



Entwurfsmuster (design patterns) sind bewährte Lösungen für wiederkehrende Probleme, die bei der Softwareentwicklung auftreten. In C++, mit seinem starken Typsystem, RAII und Mehrfachvererbung, gewinnen Muster eine besondere Flexibilität. Sie helfen, den Code lesbarer, wartbarer und skalierbarer zu machen.



In diesem Artikel betrachten wir 4 Schlüsselmuster aus dem GoF-Katalog (Gang of Four): Singleton, Factory Method, Observer und Strategy. Jedes Muster wird mit einem realen Codebeispiel in C++17/20 veranschaulicht.



Erzeugungsmuster: Singleton



Singleton stellt sicher, dass eine Klasse nur eine einzige Instanz hat, und bietet einen globalen Zugriffspunkt darauf. In C++ verwendet der moderne Ansatz eine lokale statische Variable (thread-safe seit C++11).



Beispiel: Anwendungs-Logger



class Logger {public:    // Kopieren und Zuweisung löschen    Logger(const Logger&) = delete;    Logger& operator=(const Logger&) = delete;

static Logger& getInstance() { static Logger instance; // thread-safe seit C++11 return instance; }

void log(const std::string& message) { std::lock_guard<std::mutex> lock(m_mutex); std::cout << "[LOG] " << message << std::endl; }

private: Logger() = default; // privater Konstruktor ~Logger() = default; std::mutex m_mutex;};

// Verwendungint main() { Logger::getInstance().log("Anwendung gestartet"); Logger::getInstance().log("Fehler: Datei nicht gefunden"); return 0;}


Vorteile: Garantie der Einzigartigkeit, faules Initialisieren, Threadsicherheit.
Nachteile: Erschwert das Testen (globaler Zustand), verletzt das Prinzip der einzigen Verantwortung.



Erzeugungsmuster: Factory Method



Factory Method definiert eine Schnittstelle zum Erstellen eines Objekts, überlässt es aber den Unterklassen, zu entscheiden, welche Klasse instanziiert wird. In C++ wird es oft durch virtuelle Funktionen und Smart Pointer implementiert.



Beispiel: Generierung verschiedener Dokumenttypen



// Abstraktes Produktclass Document {public:    virtual void open() = 0;    virtual void save() = 0;    virtual ~Document() = default;};

// Konkrete Produkteclass PDFDocument : public Document {public: void open() override { std::cout << "PDF geöffnet"; } void save() override { std::cout << "PDF gespeichert"; }};

class WordDocument : public Document {public: void open() override { std::cout << "Word geöffnet"; } void save() override { std::cout << "Word gespeichert"; }};

// Ersteller (Creator)class Application {public: virtual std::unique_ptr<Document> createDocument() = 0; virtual ~Application() = default;

void newDocument() { auto doc = createDocument(); doc->open(); // Arbeit mit dem Dokument }};

// Konkrete Erstellerclass PDFApplication : public Application {public: std::unique_ptr<Document> createDocument() override { return std::make_unique<PDFDocument>(); }};

class WordApplication : public Application {public: std::unique_ptr<Document> createDocument() override { return std::make_unique<WordDocument>(); }};

// Verwendungint main() { std::unique_ptr<Application> app = std::make_unique<PDFApplication>(); app->newDocument(); // Ausgabe: "PDF geöffnet" return 0;}


Dieses Muster ist ideal, wenn die genauen Typen der zu erstellenden Objekte im Voraus nicht bekannt sind.



Verhaltensmuster: Observer



Blogs

Buchempfehlungen