🎈 커맨드 패턴 (Command Pattern)
• 명령을 캡슐화하고 실행하기 위해 사용
• GUI 응용 프로그램, 트랜잭션 처리, 큐 관리 등에 활용 가능
• 명령 이력 관리, 역명령 실행(Undo), 동적 선택과 같은 상황에서 유용
• 디자인 패턴 중 행위 패턴에 해당된다
💻 디자인 패턴(Design Pattern)이란?
👨💻 디자인 패턴(Design Pattern)이란? • SW 개발 방법 중에서도 구조적인 문제 해결에 목적을 둔다. • 알고리즘과 같이 특정 문제를 해결하는 Logic 형태보다는 특정 상황에 적용할 수 있는 방
zoosso.tistory.com
[예제 코드] → Command Pattern
#include <iostream>
#include <vector>
class Light {
public:
void turnOn() {
std::cout << "전원 on..." << std::endl;
}
void turnOff() {
std::cout << "전원 off..." << std::endl;
}
};
class Command {
public:
virtual void execute() = 0;
};
class TurnOnLightCommand : public Command {
private:
Light& light;
public:
TurnOnLightCommand(Light& l) : light(l) {}
void execute() {
light.turnOn();
}
};
class TurnOffLightCommand : public Command {
private:
Light& light;
public:
TurnOffLightCommand(Light& l) : light(l) {}
void execute() {
light.turnOff();
}
};
// Invoker (호출자) 클래스
class RemoteControl {
private:
std::vector<Command*> commands;
public:
void addCommand(Command* cmd) {
commands.push_back(cmd);
}
void pressButton(int index) {
if (index >= 0 && index < commands.size()) {
commands[index]->execute();
}
else {
std::cout << "유효하지 않은 버튼!" << std::endl;
}
}
};
int main() {
Light light;
TurnOnLightCommand turnOnCmd(light);
TurnOffLightCommand turnOffCmd(light);
RemoteControl remote;
remote.addCommand(&turnOnCmd);
remote.addCommand(&turnOffCmd);
remote.pressButton(0); // 전원 on.
remote.pressButton(1); // 전원 off.
remote.pressButton(5); // 유효하지 않은 버튼.
return 0;
}

전원을 켜고 끄는 리모컨을 구현하였다.
Command 패턴으로 리모컨 버튼과 명령을 캡슐화 처리
[예제 코드] → Command Pattern 적용 X
명령어 패턴을 적용하지 않는다면 어떻게 될까?
#include <iostream>
class Light {
public:
void turnOn() {
std::cout << "전원을 켭니다." << std::endl;
}
void turnOff() {
std::cout << "전원을 끕니다." << std::endl;
}
};
int main() {
Light light;
// 전원 켜기
light.turnOn();
// 전원 끄기
light.turnOff();
return 0;
}

Command 패턴을 적용하지 않는다면
리모컨 버튼을 누를 때마다 직접적으로 Light 객체 메서드 호출이 필요하다.
이는 리모컨 버튼과 전원 제어 코드가 강하게 결합된 셈이다.
🎈 커맨드 패턴 장단점
+ 확장성: 새롭게 명령 추가하거나 기존 명령어 변경이 쉽다.
+ Undo 실행: 명령 이력을 기록하고 취소를 쉽게 구현할 수 있다.
+ 클라이언트 코드 간소화: 명령 수행 객체 세부 내용을 알 필요가 없어진다.
- 클래스 수 증가: 명령마다 별도의 클래스가 필요하므로 클래스 수가 증가
- 복잡성 증가: 간단한 명령의 경우 패턴 적용이 더 복잡해 보인다.
[예제 코드] → Undo 명령어
#include <iostream>
#include <string>
#include <vector>
// Receiver (장치) 클래스: 텍스트 에디터
class TextEditor {
public:
void openDocument(const std::string& document) {
std::cout << "문서 열기: " << document << std::endl;
}
void closeDocument(const std::string& document) {
std::cout << "문서 닫기: " << document << std::endl;
}
};
// Command (명령) 인터페이스
class Command {
public:
virtual void execute() = 0;
};
// ConcreteCommand (구체적인 명령) 클래스
class OpenDocumentCommand : public Command {
private:
TextEditor& editor;
std::string document;
public:
OpenDocumentCommand(TextEditor& e, const std::string& doc) : editor(e), document(doc) {}
void execute() override {
editor.openDocument(document);
}
};
class CloseDocumentCommand : public Command {
private:
TextEditor& editor;
std::string document;
public:
CloseDocumentCommand(TextEditor& e, const std::string& doc) : editor(e), document(doc) {}
void execute() override {
editor.closeDocument(document);
}
};
// Invoker (호출자) 클래스
class TextEditorInvoker {
private:
std::vector<Command*> commandHistory;
public:
void executeCommand(Command* cmd) {
cmd->execute();
commandHistory.push_back(cmd);
}
void undoLastCommand() {
if (!commandHistory.empty()) {
Command* lastCommand = commandHistory.back();
lastCommand->execute(); // 역명령 실행
commandHistory.pop_back();
}
else {
std::cout << "명령 이력이 없습니다." << std::endl;
}
}
};
int main() {
TextEditor editor;
TextEditorInvoker invoker;
// 명령 생성
OpenDocumentCommand openCmd(editor, "example.txt");
CloseDocumentCommand closeCmd(editor, "example.txt");
// 명령 실행
invoker.executeCommand(&openCmd);
invoker.executeCommand(&closeCmd);
// 명령 실행 취소 (Undo)
invoker.undoLastCommand();
return 0;
}

TextEditorInvoker 클래스는 명령을 관리하고 실행하며
실행 이력을 유지하고 명령 실행 취소를 지원한다.
🎈 다른 디자인 패턴과 비교
• Observer
관찰자 패턴은 주체(Subject)와 관찰자(Observer)를 분리하여
주체의 상태 변화를 관찰자에게 알려주는 패턴으로
주로 상태 변경 알림 및 이벤트 처리에 사용된다.
커맨드 패턴은 실행 요청을 수신하고 처리할 객체에 전달하는 것에서 비슷한 점이 보인다.
• 전략 (Strategy)
전략 패턴은 알고리즘을 정의하고, 각각을 캡슐화하며 런타임시간에 교체 가능하다.
커맨드 패턴은 명령을 객체로 캡슐화하는 것에서는 비슷한점이 있다.
💻 [디자인패턴] 전략 패턴 (Strategy Pattern)
전략 패턴 (Strategy Pattern) 이란? 전략(Strategy)은 코드 내부에서 로직(Logic)을 처리하는 「알고리즘」 어떤 목적 달성을 위한 수행 방식이라고 생각하면 좋다. 영화관에서 이벤트 영화 예매 방식을
zoosso.tistory.com
상태 패턴은 객체의 내부 상태를 변경하고
해당 상태에 따라 객체의 행동을 다르게 처리한다
상태 패턴 (State Pattern)
상태(State) 패턴이란? • 객체 내부 상태에 맞춰 스스로 행동을 변경하는 패턴 • 객체는 마치 자신의 클래스를 바꾸는 것처럼 보인다. • if-else와 같은 분기문으로 상태전이 하는 것을 해소한다.
zoosso.tistory.com
Factory 패턴은 객체를 생성하기 위한 인터페이스를 정의하고
서브클래스에서 구체적인 생성 과정 결정
주로 객체 생성 및 초기화에 사용됩니다.
팩토리 메서드 패턴 (Factory Method)
🎈 팩토리 메서드 패턴(Factory Method Pattern) • 객체 생성 시 확장을 쉽게 하기 위한 설계 방법 강력한 결합 관계는 코드의 수정•변경을 어렵게 한다. • 객체 생성 동작을 별도 클래스로 분리하
zoosso.tistory.com
'까망 동네 > 디자인 패턴' 카테고리의 다른 글
[디자인패턴] 컴포지트 패턴 (Composite Pattern) (1) | 2023.11.05 |
---|---|
[디자인패턴] 인터프리터 패턴 (Interpreter Pattern) (2) | 2023.11.04 |
[디자인패턴] 장식자 패턴 (Decorator) (2) | 2023.11.01 |
[디자인패턴] 프로토타입 (Prototype Pattern) (1) | 2023.10.31 |
[디자인 패턴] 브릿지 패턴 (Bridge Pattern) (3) | 2023.10.28 |
댓글