커맨드 패턴
(C++ 디자인 책 정리)
커맨드 디자인 패턴은 (대개) 한 번 그리고 (보통) 즉시 실행하는 작업 꾸러미의 추상화와 분리에 초점을 맞춘다.
커맨드 디자인 패턴의 의도는 다음과 같다.
의도: ' 요청을 객체로 캡슐화해 클라이언트를 다른 요청, 큐 또는 로그 요청 등으로 매개변수화하고
실행 취소할 수 있는 연산을 지원하게 한다.'

OO 기반 형식에서 커맨드 패턴은 Command 기초 클래스 형식의 추상화를 도입한다. 이를 통해 누구나 새 ConcreateCommand를 구현할 수 있다. 그 ConcreteCommand는 무엇이든 할 수 있으며 심지어 Receiver에 행동을 수행할 수도 있다.
명령 효과는 특정 Invoker가 추상 기초 클래스를 통해 유발한다.
커맨드 디자인 패턴의 구체적인 예로 다음 계산기 구현을 살펴보자. 첫 번째 코드 조각에서는 주어진 정수에 대한 수학 연산의 추상화를 나타내는 CalculatorCommand 기초 클래스 구현을 볼 수 있다.
//----- <CalculatorCommand.h> -----
class CalculatorCommand
{
public:
virtual ~CalculatorCommand() = default;
virtual int execute( int i ) const = 0;
virtual int undo ( int i ) const = 0;
};
Add와 Subtract 클래스를 구현해보자 모두 계산기에 가능한 명령을 나타내므로 CalculatorCommand 기초 클래스를 구현한다.
// ------ <Add.h> ------
class Add : public CalculatorCommand
{
public:
explicit Add( int operand ) : operand_(operand) {}
int execute( int i ) const override
{
return i + operand_;
}
int undo( int i ) const override
{
return i - operand_;
}
private:
int operand_{};
};
// ----- <Subtract.h> -----
class Subtract : public CalculatorCommand
{
public:
explicit Subtract( int operand ) : operand_(operand) {}
int execute( int i ) const override
{
return i - operand_;
}
int undo( int i ) const override
{
return i + operand_;
}
private:
int operand_{};
};
Calculator의 핵심인 Calculator 클래스는 Add, subtract 에서 명령어를 구현했기 때문에 클래스 자체는 다소 단순하게 유지할 수 있다.
//-----<Calculator.h>-----
#include "CalculatorCommand.h"
#include <stack>
class Calculator
{
public:
void compute( std::unique_ptr<CalculatorCommand> command );
void undoLast();
int result() const;
void clear();
private:
using CommandStack = std::stack<std::unique_ptr<CalculatorCommand>>;
int current_{};
CommandStack stack_;
};
//-----<Calculator.cpp>-----
include "Calculator.h"
void Calculator::compute( std::unique_ptr<CalculatorCommand> command )
{
current_ = command->execute( current_ );
stack_.push( std::move(command) );
}
void Calculator::undoLast()
{
if( stack_.empty() ) return;
auto command = std::move(stack_.top());
stack_.pop();
current_ = command->undo(current_);
}
int Calculator::result() const
{
return current_;
}
void Calculator::clear()
{
current_ = 0;
CommandStack{}.swap( stack_ ); // clear stack
}
main 함수에서 모든 조각을 결합한다.
int main()
{
Calculator calculator{};
auto op1 = std::make_unique<Add>( 4 );
auto op2 = std::make_unique<Add>( 5 );
auto op3 = std::make_unique<Add>( 6 );
auto op4 = std::make_unique<Add>( 1 );
auto op5 = std::make_unique<Subtract>( 2 );
auto op6 = std::make_unique<Subtract>( 3 );
calculator.compute( std::move(op1) );
calculator.compute( std::move(op2) );
calculator.compute( std::move(op3) );
calculator.compute( std::move(op4) );
calculator.compute( std::move(op5) );
calculator.compute( std::move(op6) );
int const res = calculator.result();
printf(" calculator : %d \n", res);
};
이 디자인은 SOLID원칙을 매우 훌륭히 따른다. 커맨드 디자인 패턴을 통해 변형점을 이미 추출했으므로 SRP를 따른다. 결과적으로 compute()와 undoLast() 모두 가상 함수일 필요가 없다. 또한 SRP는 OCP를 가능하게 하는 역할이며, 어떤 기존 코드도 수정하지 않고 새 연산을 추가할 수 있게 한다.
'Language > C++ Design Pattern' 카테고리의 다른 글
Strategy 패턴 (0) | 2025.02.09 |
---|---|
Visitor 패턴 (std::variant) (0) | 2025.02.05 |
Visitor 패턴 (1) | 2025.02.02 |
DIP 원칙 (0) | 2025.01.30 |
LSP 원칙 (0) | 2025.01.30 |