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
Here is detailed implementation code using C++. Define a class to encapsulate data and functionality and perform branching with conditionals. Understand the role of each part while examining the code.
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
Here is detailed implementation code using C++. Import the necessary modules, define a class to encapsulate data and functionality, and perform branching with conditionals. Understand the role of each part while examining the code.
#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;
}
};
Meyers Singleton (Recommended)
Below is an implementation example using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.
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
Here is detailed implementation code using C++. Define a class to encapsulate data and functionality and perform branching with conditionals. Understand the role of each part while examining the code.
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
Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.
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
Here is detailed implementation code using C++. Import the necessary modules, define a class to encapsulate data and functionality, and process data with loops. Understand the role of each part while examining the code.
#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
Here is detailed implementation code using C++. Define a class to encapsulate data and functionality and perform branching with conditionals. Understand the role of each part while examining the code.
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
- Singleton: Ensure single instance
- Factory: Encapsulate object creation
- Observer: Notify state changes
- 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
Related Articles
- C++ Function Basics
- C++ Smart Pointers
- C++ Creational Patterns
Master design patterns for better C++ architecture! 🚀
자주 묻는 질문 (FAQ)
Q. 이 내용을 실무에서 언제 쓰나요?
A. Development blog post organizing C++ design patterns. class Singleton { private: static Singleton instance; Singleton() … 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.
Q. 선행으로 읽으면 좋은 글은?
A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.
Q. 더 깊이 공부하려면?
A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- C++ 함수 | ‘처음 배우는’ 함수 만들기 완벽 가이드 [예제 10개]
- C++ 스마트 포인터 | unique_ptr/shared_ptr ‘메모리 안전’ 가이드
- C++ 메모리 관리 | ‘new/delete/RAII’ 완벽 정리
- C++ 디자인 패턴 | Singleton·Factory·Builder·Prototype 생성 패턴 가이드
- C++ 디자인 패턴 종합 가이드 | Singleton·Factory
- JavaScript 디자인 패턴 | 싱글톤, 팩토리, 옵저버 패턴
- Python 데코레이터 | @decorator 완벽 정리
이 글에서 다루는 키워드 (관련 검색어)
C++, design-pattern, singleton, OOP 등으로 검색하시면 이 글이 도움이 됩니다.