디자인 패턴 - 커맨드 패턴

LeeTaeHwa·2022년 4월 6일
0

디자인 패턴

목록 보기
1/1

커맨드 패턴

요청 자체를 캡슐화하는 것이다. 이를 통해 요청이 서로 다른 사용자를 매개변수
로 만들고, 요청을 대기시키거나 로깅하여, 되돌릴 수 있는 연산을 지원한다.

*GoF의 디자인 패턴 발췌

설명이 어딘가 난해하고 어렵다. 이해 못 할 설명을 100번 봐서 무얼 하겠는가. 백문이 불여일견이라고, 예제를 통해 살펴 보도록하자.

다들 1번 쯤은 플레이 해봤을 법한 게임을 예제로 살펴보도록하자. 리그 오브 레전드에서 사용자 입력은 몇 가지 경우로 제한된다. 캐릭터를 이동시키는 마우스 조작, 인벤토리에서 아이템 사용, 그리고 스킬조작이다.

이 스킬조작은 리그 오브 레전드를 플레이 함에 있어 가장 많이 사용되는 커맨드라고 자신 할 수 있다. 스킬조작의 인터페이스는 Q, W, E, R 입력과 스펠 커맨드인 D, F로 나뉜다.

그렇다면 우리가 만약에 이를 구현 한다면 어떻게 디자인을 할까? 다음과 같은 예시를 한번 보도록 하자.

void PlayerInput::handleInput() {
	if(pressed(Q)) rangerFocus();
    else if(pressed(W)) volley();
    else if(pressed(E)) hawkshot();
    else if(pressed(R)) crystalArrow();
}

딱 봐도 무엇을 할 것인지 알기가 쉽다. 하지만 이런 방식에는 문제가 있다. 보통 게임들이 키를 바꿀 수 있도록 해준다는 점을 생각해보자. 즉, 입력 키를 바꾸기가 곤란한 구조다.

다음과 같은 접근법을 살펴보도록하자.

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

일단 커맨드에 대한 순수 가상 함수 클래스부터 구현해주자.

class TigerStance : public Command {
public:
	virtual void execute() { tigerBuff(); }
    //Udyr stance change
};

그리고 각자 행위에 맞는 커맨드를 구현해준다.

class PlayerInput {
public:
	void handleInput();
private:
	Command* qSkill;
    Command* wSkill;
    Command* eSkill;
    Command* rSkill;
};

void PlayerInput::handleInput() {
	if(pressed(BUTTON_Q) qSkill->execute();
    else if(pressed(BUTTON_W) wSkill->execute();
    else if(pressed(BUTTON_E) eSkill->execute();
    else if(pressed(BUTTON_R) rSkill->execute();
}

여기까지가 커맨드 패턴의 핵심적인 내용들이다.

커맨드 패턴 - 액터

하지만 위의 예시를 보면 어딘가 위화감이 든다. 바로 플레이 중인 캐릭터에 대한 전역 변수라는 가정이 깔려있다. 이는 유연성이 떨어지는 접근법이다. 다음과 같은 접근법을 살펴보도록 하자.

class Command {
public:
	virtual ~Command() { }
    virtual void execute(Champion& champ) = 0;
};

Champion 객체를 입력으로 받아 해당 챔피언의 스킬을 사용하는 방식으로 접근해보자.

class QSkillCommand : Command {
public:
	virtual void execute(Champion& champ) {
    	champ.qSkill();
    }
};

이로써 챔피언의 스킬을 유연하게 사용하는 것이 가능해졌다. 하지만 이런 예시 또한 어딘가 위화감이 든다. 보통의 경우엔 플레이어가 조종하는 챔피언이 바뀔일은 없다고 봐도 무방하다. 사일러스와 비에고처럼 예외적인 경우가 있지만, 대부분은 고정된 챔피언을 조종하게 된다.

하지만 AI를 다루는 경우를 생각해보자. AI는 보통 Agent 객체를 생성하여 다루는데, 이 Agent들을 제어하기 위한 인터페이스로 커맨드 패턴을 활용 할 수도 있다.

profile
하늘을 향해 걸어가고 있습니다.

0개의 댓글