커맨드 패턴

주상돈·2025년 3월 25일

TIL

목록 보기
43/53

커맨드 패턴(Command Pattern)

커맨드 패턴(Command Pattern) 은 요청(명령)을 객체의 형태로 캡슐화하여, 요청을 보내는 객체와 처리하는 객체를 서로 분리시키는 디자인 패턴이다.

즉, 특정 작업이나 요청을 하나의 객체로 만들어 두면 이 객체를 재사용하거나, 필요에 따라 요청 실행을 나중으로 미루거나, 취소하는 등의 작업을 쉽게 할 수 있다.


커맨드 패턴의 목적과 장점

커맨드 패턴은 다음과 같은 목적과 장점을 가지고 있다.

  • 요청과 실행의 분리 명령을 요청하는 객체가 실제 명령을 처리하는 방법을 알 필요가 없다.
  • 명령의 큐(Queue) 명령 객체들을 저장하고 관리하여 원하는 시점에 실행하거나 재실행할 수 있다.
  • 작업의 취소(Undo) 및 재실행(Redo) 명령 객체를 기록하면 작업의 취소와 재실행 기능을 쉽게 구현할 수 있다.
  • 확장성 새로운 명령을 추가할 때 기존의 코드를 거의 변경하지 않고 쉽게 추가할 수 있다.

커맨드 패턴의 구성 요소

커맨드 패턴은 주로 다음과 같은 구성 요소로 이루어져 있다.

요소역할
Command명령을 수행하는 데 필요한 인터페이스
ConcreteCommandCommand를 구현한 실제 명령 객체
Invoker명령 객체를 요청하고 실행하는 호출자
Receiver실제 명령을 수행할 책임을 가진 객체

커맨드 패턴 활용 예시 (C++)

Command 인터페이스

class ICommand {
public:
    virtual void execute() = 0;
    virtual void undo() = 0;
    virtual ~ICommand() {}
};

Receiver 클래스 (실제 동작 구현)

class Light {
public:
    void turnOn() {
        std::cout << "불을 켭니다." << std::endl;
    }
    void turnOff() {
        std::cout << "불을 끕니다." << std::endl;
    }
};

ConcreteCommand 클래스 (구체적 명령)

class LightOnCommand : public ICommand {
private:
    Light* light;
public:
    LightOnCommand(Light* l) : light(l) {}
    void execute() override {
        light->turnOn();
    }
    void undo() override {
        light->turnOff();
    }
};

class LightOffCommand : public ICommand {
private:
    Light* light;
public:
    LightOffCommand(Light* l) : light(l) {}
    void execute() override {
        light->turnOff();
    }
    void undo() override {
        light->turnOn();
    }
};

Invoker 클래스 (명령 요청자)

class RemoteControl {
private:
    ICommand* command;
public:
    void setCommand(ICommand* c) {
        command = c;
    }
    void pressButton() {
        command->execute();
    }
    void pressUndo() {
        command->undo();
    }
};

사용 예시

int main() {
    Light livingRoomLight;

    LightOnCommand lightOn(&livingRoomLight);
    LightOffCommand lightOff(&livingRoomLight);

    RemoteControl remote;

    // 불 켜기 명령 실행
    remote.setCommand(&lightOn);
    remote.pressButton();

    // 불 끄기 명령 실행
    remote.setCommand(&lightOff);
    remote.pressButton();

    // 직전 명령 취소 (불 켜기)
    remote.pressUndo();

    return 0;
}

실행 결과

복사편집
불을 켭니다.
불을 끕니다.
불을 켭니다.

게임 개발에서의 커맨드 패턴 활용 예시

게임에서도 커맨드 패턴이 자주 사용됩니다. 예를 들면:

  • 키 입력 처리 키 입력마다 명령 객체를 생성하면 입력의 재정의, 반복 실행, 취소 등이 쉬워진다.
  • 액션 재생 및 녹화 플레이어의 행동을 명령 객체로 기록하면, 행동을 다시 재현하거나 되돌릴 수 있다.
  • 게임 이벤트 처리 여러 가지 게임 내 이벤트를 객체화하여 관리하면 유연하고 유지보수가 용이해진다.

커맨드 패턴을 사용할 때의 주의점

커맨드 패턴이 유용하다고 해서 모든 요청을 무조건 객체로 만드는 것은 바람직하지 않다.

너무 많은 명령 객체 생성은 메모리 소모가 많아질 수 있고 단순한 기능에 사용하면 오히려 코드가 복잡해질 수 있기 때문이다.

즉, 명령의 실행, 취소, 재실행, 기록과 같은 특수한 관리가 필요한 경우 커맨드 패턴을 적극적으로 사용하는 것이 좋다.

0개의 댓글