
그동안 디자인 패턴중에 생성 패턴, 구조패턴에 대해서 배웠다. 그렇다면 마지막으로 행동 패턴에 대해서 배우면 디자인 패턴은 어느정도 알게 된것이다.
객체간의 상호작용과 책임 분산을 다루는 디자인 패턴이다.
- 객체 간 결합도를 줄이기
- 재사용성과 유연성을 높인다.
요청을 처리할 수 있는 객체들을 체인처럼 연결을하고, 각 객체가 자신이 처리할 수 없는 일이면 다음 객체로 넘긴다.
Client → Button → Dialog → Widget → Application

class HelpHandler {
protected:
HelpHandler* successor;
public:
HelpHandler(HelpHandler* next) : successor(next) {}
virtual void HandleHelp() {
if (successor != nullptr) {
successor->HandleHelp(); // 다음 책임자에게 넘김
} else {
cout << "[기본 도움말 없음]" << endl;
}
}
virtual ~HelpHandler() {}
};
class Button : public HelpHandler {
public:
Button(HelpHandler* next) : HelpHandler(next) {}
void HandleHelp() override {
cout << "[Button 도움말]" << endl;
}
};
class Dialog : public HelpHandler {
public:
Dialog(HelpHandler* next) : HelpHandler(next) {}
void HandleHelp() override {
cout << "[Dialog 도움말]" << endl;
}
};
class Application : public HelpHandler {
public:
Application(HelpHandler* next) : HelpHandler(next) {}
void HandleHelp() override {
cout << "[Application 도움말]" << endl;
}
};
int main() {
Application* app = new Application(nullptr);
Dialog* dialog = new Dialog(app);
Button* button = new Button(dialog);
// 가장 하위 객체에서 요청 시작
button->HandleHelp();
delete button;
delete dialog;
delete app;
return 0;
}
실행결과: [Button 도움말]

다시 한번 그림을 확인해보자.
최상위 HelpHandler가 successor으로 자신을 참조한다.
정확히는 자신 보다는 다음 체인에 들어올 객체를 참조하는 것.
만약 도움말이 없으면 다음 객체로 책임을 넘기려고 한다면, boolean값을 하나 만들어서 help가 있는지 유무를 확인하고 없으면 다음으로 넘기게 Button, Dialog 클래스에서 추가하면 된다.
요청을 객체로 캡슐화 해서 요청자와 수행자를 분리하고 요청을 저장, 실행 할 수 있게 만드는 행동 패턴이다.

class Command {
public:
virtual void Execute() = 0;
virtual ~Command() {}
};
class CopyCommand : public Command {
public:
void Execute() override {
cout << "복사 실행됨" << endl;
}
};
class PasteCommand : public Command {
public:
void Execute() override {
cout << "붙여넣기 실행됨" << endl;
}
};
class UndoCommand : public Command {
public:
void Execute() override {
cout << "실행 취소됨" << endl;
}
};
class MenuItem {
private:
Command* command;
public:
MenuItem(Command* cmd) : command(cmd) {}
void OnClicked() {
command->Execute(); // 버튼이 클릭되면 명령 실행
}
};
int main() {
Command* copy = new CopyCommand();
Command* paste = new PasteCommand();
MenuItem copyItem(copy);
MenuItem pasteItem(paste);
copyItem.OnClicked(); // 복사 실행됨
pasteItem.OnClicked(); // 붙여넣기 실행됨
delete copy;
delete paste;
return 0;
}
[실행 결과]: 복사 실행됨 , 붙여넣기 실행됨
게임으로 예시를 들어보자면, 팝업창을 애니메이션을 넣어서 띄우게 되는데 여러 애니메이션 중에서 선택해서 실행시키면 action하게 만들 수 있다.
✅ Command 패턴은 명령을 객체로 만들어서 관리한다는 점이 핵심!!
컬렉션 내부 구조를 노출하지 않고, 요소를 하나씩 순차적으로 접근할 수 있는 방법을 제공하는 패턴

목적: ByValueList라는 컬렉션을 직접 순회하지 않고 Iterator를 이용해서 추상적으로 하나씩 접근할 수 있게 만든다.
class MyList {
private:
int data[3] = {10, 20, 30};
public:
int get(int index) { return data[index]; }
int size() { return 3; }
};
class Iterator {
private:
MyList* list;
int index = 0;
public:
Iterator(MyList* l) : list(l) {}
void first() { index = 0; }
void next() { index++; }
bool isDone() { return index >= list->size(); }
int currentItem() { return list->get(index); }
};
int main() {
MyList list;
Iterator it(&list);
for (it.first(); !it.isDone(); it.next()) {
cout << it.currentItem() << " ";
}
return 0;
}
출력 결과: 10 20 30
여러 객체 간의 복잡한 상호작용을 중앙 집중식으로 조율하는 "중재자" 객체를 만들어, 객체 간 직접 통신을 막고, 결합도를 낮추는 행동 패턴.
class Mediator {
public:
virtual void Notify(const string& sender, const string& event) = 0;
virtual ~Mediator() {}
};
class Component {
protected:
Mediator* mediator;
public:
void SetMediator(Mediator* m) { mediator = m; }
};
class Button : public Component {
public:
void Click() {
cout << "[Button 클릭됨]\n";
mediator->Notify("Button", "Click");
}
};
class TextBox : public Component {
public:
void ShowText(const string& msg) {
cout << "[TextBox 출력] " << msg << endl;
}
};
class DialogMediator : public Mediator {
private:
Button* button;
TextBox* textbox;
public:
DialogMediator(Button* b, TextBox* t) : button(b), textbox(t) {
button->SetMediator(this);
textbox->SetMediator(this);
}
void Notify(const string& sender, const string& event) override {
if (sender == "Button" && event == "Click") {
textbox->ShowText("버튼이 눌렸습니다");
}
}
};
int main() {
Button* btn = new Button();
TextBox* txt = new TextBox();
DialogMediator* mediator = new DialogMediator(btn, txt);
btn->Click(); // → TextBox가 자동으로 반응
delete mediator;
delete btn;
delete txt;
return 0;
}
메멘토는 객체의 내부 상태를 저장해두었다가 나중에 그 상태로 되돌릴 수 있게 하는 패턴이다.
- 보통 Undo를 위해 사용된다.

어떤 객체가 상태가 바뀌면 그와 의존하고 있던 옵저버에게 알림을 보내는 구조.
보통 이벤트를 다루기 위해서 많이 사용한다.

class Observer {
public:
virtual void Update(const string& message) = 0;
virtual ~Observer() {}
};
먼저 옵저버 인터페이스를 만든다.
class Subject {
public:
virtual void Attach(Observer* o) = 0;
virtual void Detach(Observer* o) = 0;
virtual void Notify() = 0;
virtual ~Subject() {}
};
class NewsAgency : public Subject {
private:
vector<Observer*> observers;
string latestNews;
public:
void Attach(Observer* o) override {
observers.push_back(o);
}
void Detach(Observer* o) override {
observers.erase(remove(observers.begin(), observers.end(), o), observers.end());
}
void SetNews(const string& news) {
latestNews = news;
Notify(); // 상태가 바뀌면 자동 알림
}
void Notify() override {
for (Observer* o : observers) {
o->Update(latestNews);
}
}
};
class Subscriber : public Observer {
private:
string name;
public:
Subscriber(const string& n) : name(n) {}
void Update(const string& message) override {
cout << name << "님에게 뉴스 도착: " << message << endl;
}
};
int main() {
NewsAgency agency;
Subscriber s1("홍길동");
Subscriber s2("김철수");
agency.Attach(&s1);
agency.Attach(&s2);
agency.SetNews("🚨 속보: 디자인 패턴 시험 출제!");
// 둘 다 알림 받음
agency.Detach(&s1);
agency.SetNews("📢 공지: 점심시간 연장됨");
//S2만받음
return 0;
}
홍길동님에게 뉴스 도착: 🚨 속보: 디자인 패턴 시험 출제!
김철수님에게 뉴스 도착: 🚨 속보: 디자인 패턴 시험 출제!
김철수님에게 뉴스 도착: 📢 공지: 점심시간 연장됨
객체의 상태에 따라 행동이 달라질 때, 그 상태를 객체로 분리해서 상태 전환과 행동을 깔끔하게 관리하는 패턴이다.
- 하나의 객체가 상태에 따라 행동이 달라질때 사용.

class LightState {
public:
virtual void Toggle(class Light* light) = 0;
virtual ~LightState() {}
};
class Light {
private:
LightState* state;
public:
Light(LightState* initialState) : state(initialState) {}
void SetState(LightState* newState) {
state = newState;
}
void PressButton() {
state->Toggle(this); // 현재 상태에 동작 위임
}
};
class OnState : public LightState {
public:
void Toggle(Light* light) override {
cout << "💡 전등을 끕니다.\n";
static OffState off; // 전환할 상태를 정적 객체로 생성
light->SetState(&off);
}
};
class OffState : public LightState {
public:
void Toggle(Light* light) override {
cout << "🔆 전등을 켭니다.\n";
static OnState on;
light->SetState(&on);
}
};
int main() {
static OffState off; // 초기 상태는 꺼짐
Light light(&off);
light.PressButton(); // 🔆 전등을 켭니다.
light.PressButton(); // 💡 전등을 끕니다.
light.PressButton(); // 🔆 전등을 켭니다.
return 0;
}
행동을 객체로 캡슐화해서, 동적으로 알고리즘을 교체할 수 있도록 만드는 패턴이다.

class WeaponStrategy {
public:
virtual void Attack() = 0;
virtual ~WeaponStrategy() {}
};
class Sword : public WeaponStrategy {
public:
void Attack() override {
cout << "⚔️ 검으로 공격!" << endl;
}
};
class Bow : public WeaponStrategy {
public:
void Attack() override {
cout << "🏹 활로 공격!" << endl;
}
};
class Character {
private:
WeaponStrategy* weapon;
public:
Character(WeaponStrategy* w) : weapon(w) {}
void SetWeapon(WeaponStrategy* w) {
weapon = w;
}
void Attack() {
weapon->Attack(); // 전략에 따라 공격 방식 결정
}
};
int main() {
Sword sword;
Bow bow;
Character hero(&sword); // 처음엔 검
hero.Attack(); // ⚔️ 검으로 공격!
hero.SetWeapon(&bow); // 활로 교체
hero.Attack(); // 🏹 활로 공격!
return 0;
}
알고리즘의 뼈대(골격)는 상위 클래스에서 정의하고, 그 구체적인 세부 단계는 하위 클래스에서 구현하도록 하는 디자인 패턴이다.

class Document {
public:
void Print() { // Template Method
Header();
Body();
Footer();
}
virtual void Header() {
cout << "[기본 헤더]\n";
}
virtual void Footer() {
cout << "[기본 푸터]\n";
}
virtual void Body() = 0; // 꼭 자식이 구현해야 함
virtual ~Document() {}
};
class Report : public Document {
public:
void Body() override {
cout << "📄 리포트 본문 출력\n";
}
};
class Invoice : public Document {
public:
void Header() override {
cout << "[💼 인보이스 헤더]\n";
}
void Body() override {
cout << "💰 청구서 본문 출력\n";
}
void Footer() override {
cout << "[📌 인보이스 푸터]\n";
}
};
int main() {
Report report;
Invoice invoice;
cout << "=== 리포트 출력 ===\n";
report.Print();
cout << "\n=== 인보이스 출력 ===\n";
invoice.Print();
return 0;
}
메인에서는 각 객체를 생성해 사용하면 된다.
우리가 많은 패턴을 배웠는데 자식이 부모 클래스를 구체화 하는 흐름은 사실 많이 봐왔다.
Template Method는 보통 다른 디자인 패턴에 많이 붙어서 사용된다.