Thinking Different






Command Pattern - 커멘드 패턴


  • 메소드(작업 요청)을 객체의 형태로 캡슐화하는 것이 가장 큰 목적이다.
  • 특정한 일을 하는 기능들을 따로따로 객체화하여 요청의 종류와는 무관하게 프로그램 작성이 가능하게 만들어준다





샘플 코드)

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
//------------------------------------------------------------------
// Receiver 클래스
class Receiver
{
public:
    void action() { cout << "Receiver: To do something..." << endl; }
};
 
//------------------------------------------------------------------
// Command 인터페이스
class Command
{
public:
    virtual void execute() = 0;
};
 
//------------------------------------------------------------------
// ConcreteCommand 상속 클래스
class ConcreteCommand : public Command
{
public:
    void setReceiver(Receiver* r) { pReceiver = r; }
    void execute() override { pReceiver->action(); }
 
private:
    Receiver *pReceiver;
};
 
//------------------------------------------------------------------
// Invoker 클래스
class Invoker
{
public:
    void SetCommand(Command* command) { pCommand = command; }
    void Execute() { pCommand->execute(); }
 
private:
    Command* pCommand;
};
 
//------------------------------------------------------------------
// Main
int _tmain(int argc, _TCHAR* argv[])
{
    Invoker mInvoker;
    Receiver mReceiver;
    ConcreteCommand mCommand;
 
    mCommand.setReceiver(&mReceiver);
    mInvoker.SetCommand(&mCommand);
    mInvoker.Execute();
 
    return 0;
}




예제를 통한 커멘드 패턴(Command Pattern) 알아보기



예제) 파일 메뉴 명령 처리 예제



각각의 명령(파일생성, 저장, 닫기) 3개의 명령을 두고 처리자는 명령을 받아서 리시버에서 명령에 대한 세부내용을 처리한다.



예제 코드)

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//------------------------------------------------------------------
// Receiver 인터페이스
class Receiver
{
public:
    virtual void 실행() = 0;
};
 
//------------------------------------------------------------------
// 파일생성 클래스
class 파일생성 : public Receiver
{
public:
    virtual void 실행() override { cout << "파일 생성" << endl; }
};
 
//------------------------------------------------------------------
// 파일저장 클래스
class 파일저장 : public Receiver
{
public:
    virtual void 실행() override { cout << "파일 저장" << endl; }
};
 
//------------------------------------------------------------------
// 파일닫기 클래스
class 파일닫기 : public Receiver
{
public:
    virtual void 실행() override { cout << "파일 닫기" << endl; }
};
 
//------------------------------------------------------------------
// Command 인터페이스
class Command
{
public:
    virtual void 실행() = 0;
};
 
//------------------------------------------------------------------
// 파일 생성 명령 클래스
class 파일생성명령 : public Command
public:
    void 리시버설정(Receiver* r) { pReceiver = r; }
    void 실행() { pReceiver->실행(); }
 
private:
    Receiver* pReceiver;
};
 
//------------------------------------------------------------------
// 파일 저장 명령 클래스
class 파일저장명령 : public Command
{
public:
    void 리시버설정(Receiver* r) { pReceiver = r; }
    void 실행() { pReceiver->실행(); }
 
private:
    Receiver* pReceiver;
};
 
//------------------------------------------------------------------
// 파일 닫기 명령 클래스
class 파일닫기명령 : public Command
{
public:
    void 리시버설정(Receiver* r) { pReceiver = r; }
    void 실행() { pReceiver->실행(); }
 
private:
    Receiver* pReceiver;
};
 
//------------------------------------------------------------------
// 처리자 클래스
class 처리자
{
public:
    void 명령지정(Command* pCmd) { pCommand = pCmd; }
    void 명령실행() { pCommand->실행(); }
 
private:
    Command* pCommand;
};
 
 
//------------------------------------------------------------------
// Main
int _tmain(int argc, _TCHAR* argv[])
{
    처리자 pInvoker;
    파일생성 pFileNew;
    파일생성명령 pCommand;
 
    pCommand.리시버설정(&pFileNew);
    pInvoker.명령지정(&pCommand);
    pInvoker.명령실행();
 
    return 0;
}


예제 결과)







코드 중복 해결을 위한 Template 활용


위 코드나 다이어그램에서 보는것처럼 Command 명령이 늘어남에 따라 코드 중복과 함께 코드의 양도 늘어날 수 밖에 없게 되는데, 이에 대해 해결을 위해 template를 활용하여 command 클래스를 단순화 시키도록 한다



예제) Template를 활용한 파일 메뉴 명령 처리 예제



그림에서 보는것과 같이 Command 클래스를 Template으로 단순화시켜 작성하였으며, Invoke(처리자) 클래스는 사용하지 않았다.



Template 적용 예제 코드)

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
60
61
62
//------------------------------------------------------------------
// Receiver 인터페이스
class Receiver
{
public:
    virtual void 실행() = 0;
};
 
//------------------------------------------------------------------
// 파일생성 클래스
class 파일생성 : public Receiver
{
public:
    virtual void 실행() override { cout << "파일 생성" << endl; }
};
 
//------------------------------------------------------------------
// 파일저장 클래스
class 파일저장 : public Receiver
{
public:
    virtual void 실행() override { cout << "파일 저장" << endl; }
};
 
//------------------------------------------------------------------
// 파일닫기 클래스
class 파일닫기 : public Receiver
{
public:
    virtual void 실행() override { cout << "파일 닫기" << endl; }
};
 
//------------------------------------------------------------------
// Command 인터페이스
template<typename T>
class Command
{
public:
    Command(T* receiver) : pReceiver(receiver) {}
    ~Command() { if (pReceiver) delete pReceiver; }
 
public:
    void 실행() { pReceiver->실행(); }
 
private:
    T* pReceiver;
};
 
//------------------------------------------------------------------
// Main
int _tmain(int argc, _TCHAR* argv[])
{
    Command<파일생성> pCommand1(new 파일생성());
    Command<파일저장> pCommand2(new 파일저장());
    Command<파일닫기> pCommand3(new 파일닫기());
 
    pCommand1.실행();
    pCommand2.실행();
    pCommand3.실행();
 
    return 0;
}


Template 적용 예제 결과)