반응형

블로그 이미지

 

 

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include<iostream>
#include<string>
#include<vector>
 
 
class Actor
{
public:
    virtual void jump() {
        std::cout << _who << "\t";
    }
 
    virtual void Attack() {
        std::cout << _who << "\t";
    }
 
    virtual void Walk(float speed) {
        std::cout << _who << speed << "만큼 \t";
    }
    std::string _who;
};
 
class Player : public Actor
{
public:
    Player() {
        _who = "Player";
    }
    void jump() {
        Actor::jump();
        std::cout << "점프" << std::endl;
    }
 
    void Attack() {
        Actor::Attack();
        std::cout << "공격" << std::endl;
    }
 
void Walk(float speed) {
Actor::Walk(speed);
        std::cout << "걷기" << std::endl;
    }
 
};
 
class AI : public Actor
{
public :
    AI() {
        _who = "AI";
    }
    void jump() {
        Actor::jump();
        std::cout << "점프" << std::endl;
    }
 
    void Attack() {
        Actor::Attack();
        std::cout << "공격" << std::endl;
    }
 
void Walk(float speed) {
Actor::Walk(speed);
        std::cout << "걷기" << std::endl;
    }
 
};
 
cs

 

 

 

 

여기 부터는 명령들을 클래스화 시켜서 추상화

 

부모 클래스에만 virtual  붙였다고 구조가 복잡해지면 자식함수가 불리지 않는다는 

몰상식한 발언은 삼가합시다

이런 사람의 케이스는 구조가 복잡해져서 호출이 안되는게 아니라 어딘가 잘못 만들어 놓고

왜 호출이 안되는지 이해를 못하는 경우입니다 ( more practice with C++ )

(예전에 이런 무식한 발언을 한 사람이 있었기에 생각나서 적어봄... 그냥 흘려 들으시길..)

virtual 을 자식에 붙이는건 그냥 관용적인 표현임..

 

 

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class Command
{
public :
    virtual void execute(Actor* actor) = 0;
};
 
class JumpCommand : public Command
{
public:
    void execute(Actor* actor)
    {
        actor->jump();
    }
};
 
class AttackCommand : public Command
{
public:
    void execute(Actor* actor)
    {
        actor->Attack();
    }
};
 
class WalkCommand : public Command
{
public:
WalkCommand(float speed) : _speed(speed)
{
}
    void execute(Actor* actor)
    {
        actor->walk(_speed);
    }
float _speed;
};
 
 
//여기부트는 메인 구문
int main()
{
 
    //명령들을 한데 모읍니다
    std::vector<Command*> commandNodes;
 
    JumpCommand ji;
    AttackCommand ai;
    commandNodes.push_back(&ji);
    commandNodes.push_back(&ai);
 
    //이련 명령들을 쌓아놓으면 실행 취소와 재 실행 또한 구현 할 수 있다
 
 
    Player pIns;
    AI aIns;
 
    for each (auto node in commandNodes)
    {
        node->execute(&pIns);        //액터에 명령 전송
    }
 
    std::cout << std::endl;
 
    for each (auto node in commandNodes)
    {
        node->execute(&aIns);
    }
    
 
    return 0;
}
 
cs

 

 


 

 

 

 

실행 결과

 

Player  점프

Player  공격

 

AI      점프

AI      공격

 

 

Actor 에 어떤 동작이 있다는 것이 정해져 있고 실행할 명령들을 모아 한번에 처리 ㄱ ㄱ

 

 

 

 

실행 취소는 

 

 

class DoCommand
{
public :
    virtual void do(Actor* actor) = 0;
};

 

 

class UnDoCommand
{
public :
    virtual void undo(Actor* actor) = 0;
};
 

 

 

 

 

여기서 알 수 있는 것은 Command 를 상속 받는 자식 Command 클래스들은 내부를 좀 더 자유롭게 작성 할 수 있다는 것을 알 수 있게 된다,

 

그래서

 

의 Command 들이 있다고 했을때 DoCommand 를 통과하명 명령이 실행 되고

 

UnDoCommand 를 명령어들이 통과되면 반대로 실행 되도록 하위 클래스에서 인자 값들을 조정 구현 해 주면 된다

 

 

 

 

또한 이렇게 두가지 Command 를 두는것도 있지만 명령들을 한대 놔두고 새로운 인스턴스 Actor 를 만들어 그동안 쌓아왔던 명령들을 원하는 부분까지 실행 시키게 하면 그것또한 실행 취소가 가능한 방법이다

 

 

함수 인자를 (람다 ~ Closure 클로저) 로 처리하여 좀 더 유연하게 처리 할 수도 있다

관련 글 http://3dmpengines.tistory.com/1593

 

 

 

반응형

+ Recent posts