본문으로 건너뛰기 C++ Design Patterns — Complete Guide

C++ Design Patterns — Complete Guide

C++ Design Patterns — Complete Guide

이 글의 핵심

class Singleton { private: static Singleton instance; Singleton() {}.

Same singleton/factory ideas are frequently used in JavaScript and Python decorators. For advanced topics, see C++ Creational Patterns Guide and Comprehensive Guide.

1. Singleton Pattern

Basic Implementation

class Singleton {
private:
    static Singleton* instance;
    
    Singleton() {}  // private constructor
    
public:
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    
    static Singleton* getInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
};

Singleton* Singleton::instance = nullptr;

Thread-Safe Singleton

#include <mutex>

class ThreadSafeSingleton {
private:
    static ThreadSafeSingleton* instance;
    static mutex mtx;
    
    ThreadSafeSingleton() {}
    
public:
    static ThreadSafeSingleton* getInstance() {
        if (instance == nullptr) {
            lock_guard<mutex> lock(mtx);
            if (instance == nullptr) {
                instance = new ThreadSafeSingleton();
            }
        }
        return instance;
    }
};
class MeyersSingleton {
private:
    MeyersSingleton() {}
    
public:
    static MeyersSingleton& getInstance() {
        static MeyersSingleton instance;  // Thread-safe from C++11
        return instance;
    }
    
    MeyersSingleton(const MeyersSingleton&) = delete;
    MeyersSingleton& operator=(const MeyersSingleton&) = delete;
};

2. Factory Pattern

Simple Factory

enum class ShapeType { Circle, Rectangle, Triangle };

class Shape {
public:
    virtual void draw() = 0;
    virtual ~Shape() {}
};

class Circle : public Shape {
public:
    void draw() override { cout << "Drawing circle" << endl; }
};

class Rectangle : public Shape {
public:
    void draw() override { cout << "Drawing rectangle" << endl; }
};

class ShapeFactory {
public:
    static unique_ptr<Shape> createShape(ShapeType type) {
        switch (type) {
            case ShapeType::Circle:
                return make_unique<Circle>();
            case ShapeType::Rectangle:
                return make_unique<Rectangle>();
            default:
                return nullptr;
        }
    }
};

int main() {
    auto shape = ShapeFactory::createShape(ShapeType::Circle);
    shape->draw();
}

Abstract Factory

class Button {
public:
    virtual void render() = 0;
    virtual ~Button() {}
};

class WindowsButton : public Button {
public:
    void render() override { cout << "Windows button" << endl; }
};

class MacButton : public Button {
public:
    void render() override { cout << "Mac button" << endl; }
};

class GUIFactory {
public:
    virtual unique_ptr<Button> createButton() = 0;
    virtual ~GUIFactory() {}
};

class WindowsFactory : public GUIFactory {
public:
    unique_ptr<Button> createButton() override {
        return make_unique<WindowsButton>();
    }
};

class MacFactory : public GUIFactory {
public:
    unique_ptr<Button> createButton() override {
        return make_unique<MacButton>();
    }
};

3. Observer Pattern

#include <vector>
#include <algorithm>

class Observer {
public:
    virtual void update(int value) = 0;
    virtual ~Observer() {}
};

class Subject {
private:
    vector<Observer*> observers;
    int state;
    
public:
    void attach(Observer* observer) {
        observers.push_back(observer);
    }
    
    void detach(Observer* observer) {
        observers.erase(
            remove(observers.begin(), observers.end(), observer),
            observers.end()
        );
    }
    
    void setState(int newState) {
        state = newState;
        notify();
    }
    
    void notify() {
        for (auto observer : observers) {
            observer->update(state);
        }
    }
};

class ConcreteObserver : public Observer {
private:
    string name;
    
public:
    ConcreteObserver(string n) : name(n) {}
    
    void update(int value) override {
        cout << name << " received update: " << value << endl;
    }
};

int main() {
    Subject subject;
    
    ConcreteObserver obs1("Observer1");
    ConcreteObserver obs2("Observer2");
    
    subject.attach(&obs1);
    subject.attach(&obs2);
    
    subject.setState(10);
    subject.setState(20);
}

4. Strategy Pattern

class SortStrategy {
public:
    virtual void sort(vector<int>& data) = 0;
    virtual ~SortStrategy() {}
};

class BubbleSort : public SortStrategy {
public:
    void sort(vector<int>& data) override {
        cout << "Bubble sort" << endl;
        // Implementation...
    }
};

class QuickSort : public SortStrategy {
public:
    void sort(vector<int>& data) override {
        cout << "Quick sort" << endl;
        // Implementation...
    }
};

class Sorter {
private:
    unique_ptr<SortStrategy> strategy;
    
public:
    void setStrategy(unique_ptr<SortStrategy> s) {
        strategy = move(s);
    }
    
    void sort(vector<int>& data) {
        if (strategy) {
            strategy->sort(data);
        }
    }
};

int main() {
    Sorter sorter;
    vector<int> data = {5, 2, 8, 1, 9};
    
    sorter.setStrategy(make_unique<BubbleSort>());
    sorter.sort(data);
    
    sorter.setStrategy(make_unique<QuickSort>());
    sorter.sort(data);
}

Summary

Key Points

  1. Singleton: Ensure single instance
  2. Factory: Encapsulate object creation
  3. Observer: Notify state changes
  4. Strategy: Encapsulate algorithms

When to Use

Use design patterns when:

  • Need proven solutions
  • Want maintainable code
  • Team communication
  • Scalable architecture

Don’t use when:

  • Over-engineering simple problems
  • Forcing patterns unnecessarily
  • Team unfamiliar with patterns

Best Practices

  • ✅ Use Meyers Singleton for thread safety
  • ✅ Use smart pointers in factories
  • ✅ Prefer composition over inheritance
  • ❌ Don’t overuse patterns
  • ❌ Don’t ignore SOLID principles

Master design patterns for better C++ architecture! 🚀


Frequently Asked Questions (FAQ)

Q. When would I use this in practice?

A. Development blog post organizing C++ design patterns. class Singleton { private: static Singleton instance; Singleton() …

Q. What should I read before this?

A. Follow the previous article or related articles links at the bottom of each post to learn in sequence. See the C++ series index for the full picture.

Q. Where can I study this more deeply?

A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.


Other articles related to this topic.


Keywords Covered in This Article (Related Search Terms)

This article covers C++, design-pattern, singleton, OOP.