디자인 패턴 - 커맨드 패턴(Command pattern)

정의 : 요청을 객체 형태 캡슐화하는 것. 사용자가 보낸 요청을 나중에 이용할 수 있도록 메소드 이름, 매개변수 등 요청에 필요한 정보를 저장 또는 로깅, 취소할 수 있게 만든 패턴

명령 패턴은 메서드 호출을 실체화한 것이다.
명령 패턴은 콜백을 객체지향적으로 표현한 것.

요청을 하는 객체와 그 요청을 수행하는 객체를 분리한다.
특정 객체에 대한 특정 작업 요청을 캡슐화한다.

요청 내역을 큐에 저장하거나 로그로 기록할 수 있다.
실행된 작업을 저장해뒀다가 실행취소도 가능하다.
매개변수를 써서 여러 가지 다른 요구 사항을 집어넣을 수도 있다.

외부에서 볼 때 자신이 요청한 명령이 실제로 어떻게 처리되는지 알 수 없게 캡슐화. 그냥 execute 메소드만 호출하면 요구사항이 처리되도록 한다.


 Command는 실제로 명령을 수행할 Receiver 객체를 가지고 있다. Command에서 Execute()만 구현해두면 요청하는 쪽에서는 상세를 알 필요가 없다. Execute() 내에서 Receiver 객체를 통해 작업을 수행한다.
 Invoker는 Client로부터 전달받은 Command 객체를 통해 명령을 발동한다. Action에 따른 일련의 Command 객체들을 가지고 있을 수도 있다. 필요에 따라 명령 발동 기록을 남긴다.
 Receiver는 Command의 Execute()에서 하달받은 명령을 실제로 수행한다.
 Client는 어느 시점에 어떤 명령을 수행할지 결정한다. 명령을 수행하려면, Client 객체는 Invoker 객체로 Command 객체를 전달해야 한다.

Command, Receiver, Invoker, Client

  • Command 객체는 Receiver를 가지고 있고, Receiver의 메소드를 호출한다.(Execute(), Undo())
  • Receiver는 자신에게 정의된 메소드를 수행한다.
  • Command 객체는 Invoker 객체에 전달되어 명령을 발동하게 된다.
  • Invoker 객체는 필요에 따라 명령 발동에 대한 기록을 남길 수도 있다.
  • 하나의 Invoker에게 다수의 Command 객체가 전달될 수도 있다.
  • Client 객체는 어느 시점에서 어떤 명령을 수행할지 결정한다.
  • 명령을 실행하기 위해 Client 객체는 Invoker 객체로 Command 객체를 전달한다.
  • Invoker는 일련의 커맨드 객체를 가지고 있고, 요청이 들어왔을 때 요청받은 커맨드를 수행한다.

Command로 일련의 다른 Command들을 수행하면 여러 작업을 처리하는 매크로를 만들 수도 있다.
실행한 Command를 Invoker의 스택에 쌓아두면 Undo가 구현 가능.
실행한 Command를 Invoker의 큐에 쌓아두면 로그 구현 가능.
요청받은 Command를 Invoker의 큐에 쌓아두면 메시지 큐 등 구현 가능.

플레이어가 제어하는 캐릭터 뿐 아니라 같은 방식으로 다른 액터(AI)도 제어할 수 있다. AI 엔진과 AI 액터 사이의 인터페이스로 커맨드 패턴을 사용하면 된다. 예시2.

예시:
SomeCommand : Command { Execute(); Undo(); }
Invoker { Command[] slot; Stack<Command> history; SetCommand(slotNum, Command);  OnSomeAction(){Command[actionNum].Execute();}; }
Receiver { do something requested from Execute() }
Client { Invoker.SetCommand(SomeCommand(SomeReceiver)); Invoker.Action() }

예시2:

class JumpCommand : Command {
public:
    virtual void execute(GameActor& actor){
        actor.jump();
    }
};

Command* command = inputHandler.handleInput();
if(command) command->execute(actor);

Command* InputHandler::handleInput(){
    if(isPressed(BUTTON_X)) return buttonX;
}

댓글

이 블로그의 인기 게시물

디자인 패턴 - 더티 플래그(Dirty flag)

디자인 패턴 - 서비스 중개자 패턴(Service locator pattern)

인공지능 - 유한 상태 기계(Finite state machine)