<디자인패턴> 명령(command)
<디자인패턴> 명령(command)
명령 패턴.
GoF의 디자인패턴이라는 책에 나온 정의는
"요청 자체를 캡슐화하는 것입니다. 이를 통해 요청이 서로 다른 사용자를 매개변수로 만들고, 요청을 대기시키거나 로깅하며 ,되돌릴수 있는 연산을 지원합니다."
입니다. 처음봤을때는 무슨소린가 했는데.. 예제와 설명을보면서 내가 이해한 것은 이렇다.
예를들어 게임에서의 버튼을 입력하는 함수가 있다.(전역함수로 KeyDown,jump,Attack,Run이 있다고 가정)
void KeyInput()
{
if(KeyDown('Space')) jump();
else if(KeyDown('Z')) Attack();
else if(KeyDown('X')) Run();
}
이경우에는 특정버튼을 클릭하면 바로 해당 함수가 호출되기 때분에 키를 변경하기가 까다롭다.
(대부분의 게임들에서는 원하는 키로 키변경이 가능하다)
여기서 키변경이 가능하게 하려면, 해당키를 눌렀을때 함수를 바로 호출해 버리지 않고 어떤 절차를 거쳐서 함수가 실행되게 하면 된다.
여기서 어떤 절차를 만드는 것이 명령패턴의 핵심이다.
어떤 절차를 만들기 위해서 명령 클래스를 만든다. (의사코드)
class Command
{
public:
virtual ~Command(){}
virtual void execute() = 0; //순수가상함수
}
그리고 이제 각 행동별 하위 클래스를 만들어준다.
class JumpCommand : public Command()
{
public:
virtual void execute(){jump();}
}
class AttackCommand : public Command()
{
public:
virtual void execute(){Attack();}
}
class RunCommand : public Command()
{
public:
virtual void execute(){Run();}
}
그리고 입력을 관리하는 핸들러 클래스를 만들어주고 각 버튼별로 Command 클래스 포인터를 생성시켜서 필요할때마다 원하는 클래스를 생성후 사용한다.
class InputHandler
{
public:
void handleInput();
~~
private:
Command* ButtonZ;
Command* ButtonX;
Command* ButtonSpace;
}
이제 입력처리를 다음과 같이 한다.
void InputHandler::KeyInput()
{
if(KeyDown('Space')) ButtonSpace->execute();
else if(KeyDown('Z')) ButtonZ->execute();
else if(KeyDown('X')) ButtonX->execute();
}
이로써 할당된 클래스에 따른 execute()함수를 이용하면 특정키에 원하는 명령을 실행할 수 있게 된다.
이것을 다양하게 활용할수 있다.
1. 특정 객체를 인자로 받아서 (예를들어 플레이어,몬스터) 해당 객체에게 원하는 행동을 하게 할 수도 있고.
(객체별로 따로따로 함수를 만들필요가 없음)
2.명령을 한번 할때마다 command객체가 생성되기 때문에 이것을 잘 활용하면 했던 행동 되돌리기 등도 만들수 있다.
특정 행동별로 되돌리기 함수를 만들어놓고 생성된 객체들을 스택에 저장시킨다.
계속 명령을 실행하다 보면 다음과 같이 스택이 쌓이게 된다
(명령1) (명령2) (명령3) (명령4) 오래된 것들은 지우고 최신것들을 보관하고있다가 실행취소하면 현재명령의 되돌리기 함수를 통해 했던 명령을 취소하면 된다.
이것을 또 활용해서 명령들을 저장해두고 있다가 처음부터 순서대로 실행하면 다시보기도 만들 수 있을것 같다.
-참고: 책 게임프로그래밍 패턴