[행동 패턴] 명령 패턴 - Command
[이미지 출처 : http://www.codeproject.com]
목적
요청 자체를 캡슐화하여 , 요청이 서로 다른 사용자를 매개변수로 만들고, 요청을 대기시키거나 로깅하며, 되돌릴 수 있는 연산을 지원하기 위해서 사용합니다.
활용
- 수행할 동작을 매개변수화 하고자 할때
- 서로 다른 시간에 요청을 명시하고, 저장하며, 실행하고 싶을 때,
- 실행 취소 기능을 지원하고 싶을 떄
- 기본적인 연산의 조합으로 상위 수준의 연산을 써서 시스템을 구조화 시키고 싶을 때
장점
- 명령을 여러 개 조합해서 복합 명령을 만들 수 있습니다.
- 새로운 Command 객체를 추가하기 쉽습니다.
단점
- 명령의 취소를 반복적으로 누적될 경우에 오류가 발생될 수 있습니다.
- 취소가 되지 않는 템플릿(인자가 없거나 시스템적으로 불가)한 것들에 유의가 필요합니다.
구현
[구현 A - 게임 프로그래밍 패턴 (취소 없음)]
1 2 3 4 5 6 7 8 | class Command { public : virtual ~Command(){}; virtual void execute(GameActor& actro) = 0; }; | cs |
액터에게 지시 할 수 있도록 엑터를 참조하는 명령 추상 클래스를 정의합니다.
1 2 3 4 5 6 7 8 9 10 11 | class JumpCommand : public Command { public: virtual void execute(GameActor& actor) { actor.Jump(); } }; | cs |
점프를 하게 된다면, 해당 엑터의 행동을 실행 시키는 클래스를 명령 클래스를 상속 받아 정의합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class InputHandler { public : Command* handleInput(); private : Command* buttonX_; Command* buttonY_; Command* handeInput() { if (IsPressed(BUTTON_X)) return buttonX_; if (IsPressed(BUTTON_Y)) return buttonY_; } }; | cs |
핸들러입니다. 핸들러에 각 버튼이 눌리면 해당하는 버튼의 execute 함수를 실행합니다.
엑터가 누구던지 해당하는 명령을 수행 할 수 있습니다.
1 2 3 4 5 6 | Command* command = inputHander.handleInput(); if (command) { command->execute(actor); } | cs |
[구현 B - 게임 프로그래밍 패턴]
1 2 3 4 5 6 7 8 | class Command { public : virtual ~Command(){}; virtual void execute() = 0; virtual void undo() = 0; }; | cs |
Command 추상 클래스를 정의합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | class MoveUnitCommand : public Command { private : Unit *unit_; int x_ ,y_; int beforeX, beforeY; public : MoveUnitCommand(Unit* unit, int x, int y) : unit_(unit), x_(x), y_(y), beforeX(0), beforeY(0) { } virtual void execute() { beforeX = unit_->GetX(); beforeY = unit_->GetY(); unit_->MoveTo(x_, y_); } virtual void undo() { unit_->MoveTo(beforeX, beforeY); } }; | cs |
게임 명령 중에 이동이라는 명령의 클래스를 만들고 , Command 클래스를 상속 받습니다.
상속 받고 실행과 취소 함수를 정의합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | class InputHandler { public: Command* handeInput() { Unit* unit = GetSelectedUnit(); if (IsPressed(BUTTON_UP)) { int destY = unit->GetY() - 1; return new MoveUnitCommand(unit, unit->GetX(), destY); } if (IsPressed(BUTTON_Y)) { // 공격 , 줍기 등의 행동 //... // } return nullptr; } }; | cs |
마지막으로 핸들러에게 명령을 전달합니다.
중요한 것은 명령을 내릴 때 마다 새로운 인스턴트를 생성한다는 점 입니다.
이렇게 새로운 인스턴트를 생성하고 하나로 모아 처리하면, 한번에 여러 개의 취소 및 복구가 가능합니다.
'프로그래밍 관련 > 디자인 패턴' 카테고리의 다른 글
[행동 패턴] 반복자 패턴 - Iterator (0) | 2017.01.05 |
---|---|
[행동 패턴] 관찰자 패턴 - Observer (1) | 2016.12.22 |
[생성 패턴] 추상 팩토리 패턴 - Abstract Factory (0) | 2016.07.28 |
디자인 패턴을 공부해보자! (0) | 2016.07.28 |