Command (커맨드) 패턴 -----------------------------------------------------------------------------------------------

  커맨드 패턴이란 말그대로 명령을 내리는 패턴을 의미합니다.

  하지만 하나의 명령을 내리면 그 명령은 일반적으로 다양한 클래스에 관여될수 있습니다.

  그런경우 우리는 일반적으로 조건문과 분기문을 사용하여 처리합니다.

  하지만 지속적으로 명령에 대한 분기가 늘어난다면 늘어난다면?

  계속 코드를 수정하게 되는 경우가 많습니다.

  커맨드 패턴이란 그런경우 클라이언트를 수정하기 보다는 클래스를 분화시켜 매소드를 간략화 시키는 것이 장기적인 안목으로 더 효율적인때 사용하는 패턴입니다.

 

패턴적용 스토리 -----------------------------------------------------------------------------------------------

  이번에 적용되는 스토리는 다음과 같습니다.

  게임을 만들다보면 키의 입력에 의해서 다양한 분기가 생깁니다.

  i키를 누르면 인벤을 열고

  s키를 누르면 스킬을 쓰고.

  a를 누르면 공격을 합니다.

  이러한 키를 손쉽게 관리하고 그리고 그 명령으로 인한 수없이 많이 생길수 있는 요청들을 처리하기 위한 구조를 잡는데 커맨드 패턴은 매우 유용하게 사용될 수 있습니다.

 

uml -----------------------------------------------------------------------------------------------

  

 

 

 

 

  코드를 보면 커맨드 클래스의 하위클래스들은 자신을 통해서 명령을 실제 실행할 객체들을 포함합니다.

  커맨드 객체들은 요청에 따라서 map으로 관리되고 커맨드의 입력에 따라서 플라이웨이트 패턴의 맵에서 꺼내어져 다른 객체를 호출하게 됩니다.

   

 

코드 -----------------------------------------------------------------------------------------------

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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
#include "include.h"
 
///////// KEY
 
class KeyManager
{
private:
    map<string, string>     m_mapKey;
 
private:
    KeyManager() 
    {
        KeySetting();
    }
 
public:
    ~KeyManager() {}
 
private:
    static KeyManager* m_Inst;
 
public:
    static KeyManager* GetInst(void
    {
        if(m_Inst == NULL)
        { m_Inst = new KeyManager; }
        return m_Inst;
    }
 
    static void Destroyinst(void)
    {
        SAFE_DELETE(m_Inst);
    }
 
public:
    void KeySetting(void)
    {
        m_mapKey["i"] = "inven";
        m_mapKey["a"] = "attack";
        m_mapKey["s"] = "skill";
    }
 
    const string& GetKeyValue(const string& _Str)
    {
        return m_mapKey[_Str];
    }
};
 
KeyManager* KeyManager::m_Inst = NULL;
 
///////// CPlayerPorgress
 
class CPlayerPorgress
{
public:
    virtual void Progress() = 0;
};
 
class CInven : public CPlayerPorgress
{
public:
    virtual void Progress()
    {
        cout << "인벤을 엽니다." << endl;
        cout << "인벤에서 쿵착쿵착." << endl;
    }
};
 
class CAttact : public CPlayerPorgress
{
public:
    virtual void Progress()
    {
        cout << "공격 명령" << endl;
        cout << "공격공격!" << endl;
    }
};
 
class CSkill : public CPlayerPorgress
{
public:
    virtual void Progress()
    {
        cout << "스킬을 사용합니다" << endl;
        cout << "파이어볼" << endl;
    }
};
 
///////// PlayerPorgressManager
 
class PlayerPorgressManager
{
private:
    map<string, CPlayerPorgress*>     m_mapProgress;
 
private:
    PlayerPorgressManager(void
    {  
        m_mapProgress["i"] = new CAttact();
        m_mapProgress["a"] = new CInven();
        m_mapProgress["s"] = new CSkill();
    }
 
public:
    ~PlayerPorgressManager(void) { SAFE_DELETE_MAP(m_mapProgress); }
 
private:
    static PlayerPorgressManager* m_Inst;
 
public:
    static PlayerPorgressManager* GetInst(void
    {
        if(m_Inst == NULL)
        { m_Inst = new PlayerPorgressManager; }
        return m_Inst;
    }
 
    static void Destroyinst(void)
    {
        SAFE_DELETE(m_Inst);
    }
 
public:
    CPlayerPorgress* GetProgress(const string& _Str)
    { return m_mapProgress[_Str]; }
};
 
PlayerPorgressManager* PlayerPorgressManager::m_Inst = NULL;
 
///////// CCommand
 
class CCommand
{
public:
    virtual void CommandProgress() = 0;
};
 
class CInvenCCommand : public CCommand
{
private:
    CInven* m_Pinven;
 
public:
    CInvenCCommand() 
    {
        m_Pinven = static_cast<CInven*>(PlayerPorgressManager::GetInst()->GetProgress("i"));
    }
 
public:
    ~CInvenCCommand() { }
 
public:
    virtual void CommandProgress()
    {
        if(m_Pinven)
        { m_Pinven->Progress(); }
    }
};
 
class CAttackCCommand : public CCommand
{
private:
    CAttact* m_Attack;
 
public:
    CAttackCCommand() 
    {
        m_Attack = static_cast<CAttact*>(PlayerPorgressManager::GetInst()->GetProgress("a"));
    }
 
public:
    ~CAttackCCommand() { }
 
public:
    virtual void CommandProgress()
    {
        if(m_Attack)
        { m_Attack->Progress(); }
    }
};
 
class CSkillCCommand : public CCommand
{
private:
    CSkill* m_Skill;
 
public:
    CSkillCCommand () 
    {
        m_Skill = static_cast<CSkill*>(PlayerPorgressManager::GetInst()->GetProgress("s"));
    }
 
public:
    ~CSkillCCommand () { }
 
public:
    virtual void CommandProgress()
    {
        if(m_Skill)
        { m_Skill->Progress(); }
    }
};
 
class CCommandManager
{
private:
    map<string, CCommand*>     m_mapCommand;
 
private:
    CCommandManager() 
    {
        m_mapCommand["i"] = new CAttackCCommand();
        m_mapCommand["a"] = new CInvenCCommand();
        m_mapCommand["s"] = new CSkillCCommand();
    }
 
public:
    ~CCommandManager() { SAFE_DELETE_MAP(m_mapCommand); }
 
private:
    static CCommandManager* m_Inst;
 
public:
    static CCommandManager* GetInst(void
    {
        if(m_Inst == NULL)
        { m_Inst = new CCommandManager; }
        return m_Inst;
    }
 
    static void Destroyinst(void)
    {
        SAFE_DELETE(m_Inst);
    }
 
public:
    CCommand* GetComment(const string& _Str)
    {
        if(m_mapCommand[_Str])
        { return m_mapCommand[_Str]; }
 
        return NULL;
    }
};
 
CCommandManager* CCommandManager::m_Inst = NULL;
 
// Command.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
//
 
#include "stdafx.h"
#include "command.h"
 
#include <crtdbg.h>
 
int _tmain(int argc, _TCHAR* argv[])
{
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    //_CrtSetBreakAlloc(215);
#endif
 
    KeyManager::GetInst();
    PlayerPorgressManager::GetInst();
    CCommandManager::GetInst();
 
    bool Progresscheck = true;
    CCommand* pCommand;
    string input;
 
    while(Progresscheck)
    {
        cin >> input;
 
        pCommand = CCommandManager::GetInst()->GetComment(input);
 
        if(pCommand == NULL)
        { break; }
 
        pCommand->CommandProgress();
    }
 
 
    KeyManager::Destroyinst();
    PlayerPorgressManager::Destroyinst();
    CCommandManager::Destroyinst();
 
    return 0;
}

 

결과 ----------------------------------------------------------------------------------------------- 

 

Posted by JJOREG

Chain of Responsibility(체인 오브 레스포빌리티) 패턴 --------------------------------------------------------------------------------------------

  어떠한 객체를 생성하고 그 인스턴스에 인자값을 통해서 어떠한 요청을 하면 함수는 그에 대한 처리를 할 것입니다.

  하지만 인자값이 분명한데도 잘못된 객체에 집어넣거나.

  혹은 함수에 존재하는 예외처리가 되어 버리는 경우가 있습니다.

  또는 어떠한 요청에 대한 처리가 너무 많아서 하나의 클래스의 크기가 비대해 지는 경우가 있습니다.

  책임연쇄 패턴은 각종 요청에 대해서 그것을 처리할수 있는 객체가 존재할때가지 연속적으로 객체를 탐사하며 요청을 처리할수 있는 객체를 찾아주는 패턴입니다.

 

패턴적용 스토리 -----------------------------------------------------------------------------------------------

  이번에 적용되는 스토리는 다음과 같습니다.

  당신은 퀘스트시스템을 디자인하게 되었습니다.

  퀘스트 시스템에는 엘프, 오크, 휴먼의 종족이 있고 그에 대한 퀘스트를 할당하기 위한 npc가 각기 다르게 존재합니다.

  하나의 클래스를 통해서 각 요청을 처리할수 있지만 이렇게 되면 그에 따른 분기문과 코드량이 증가할게 뻔해 보입니다.

  이런때 유용하게 사용할수 있는 것이 책임연쇄 패턴입니다.

 

uml -----------------------------------------------------------------------------------------------

  

  코드를 보면 알겠지만 데코레이터 패턴처럼 마치 리스트와 같은 구조이다.

  상위의 추상클래스를 기준으로 각 책심을 연쇄시킬 객체들을 서로 연결합니다.

  만약 하나의 연결된 객체중 하나에 요청이 들어오면 자신이 처리할수 없는 요청일 경우에는 자신과 연결된 다음 객체로 다시 요청을 보냅니다.

  그렇게 요청을 연쇄하고 요청을 처리할수 있는 객체가 등장하면 그 요청을 처리하게 됩니다.

 

 

코드 -----------------------------------------------------------------------------------------------

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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#include "include.h"
 
enum KIND_COUNT
{    
    KIND_MAX_COUNT = 3,
    KIND_NAME_COUNT_MAX = 20, 
};
 
class CCharacter
{
private:
    char        m_szKindName[KIND_NAME_COUNT_MAX];
    char        m_szClassName[KIND_NAME_COUNT_MAX];
 
public// constructor
    CCharacter() {}
    CCharacter(char* _pKindName, char* _pClassName)
    {
        strcpy_s(m_szKindName, _pKindName);
        strcpy_s(m_szClassName, _pClassName);
    }
    ~CCharacter() {}
 
public// Set
    void SetKind(char* _pKindName)
    { strcpy_s(m_szKindName, _pKindName); }
 
    void SetClass(char* _pClassName)
    { strcpy_s(m_szClassName, _pClassName); }
 
public// Get
    char* GetKind()
    { return m_szKindName; }
 
    char* GetClass()
    { return m_szClassName; }
};
 
class QuestNpc
{
public// member parameter
    QuestNpc*            m_pQuestNpc;
    static int            m_QuestCount;
    static CCharacter*    m_Character;
 
public// constructor
    QuestNpc()
        : m_pQuestNpc(0) { }
 
    QuestNpc(QuestNpc* _pQuestNpc)
        : m_pQuestNpc(_pQuestNpc) { }
 
public// Destructor
    virtual ~QuestNpc()
    { SAFE_DELETE(m_pQuestNpc); }
 
public:
    void SetNextQuestNpc(QuestNpc* _pQuestNpc)
    { m_pQuestNpc = _pQuestNpc; }
 
public//Quest
    virtual void QuestShow()
    {
        cout << "어느 종족에도 속해있지 않은 캐릭터입니다." << endl;
        m_QuestCount = 0;
    }
    virtual void SetPlayer(CCharacter* _Character)
    {
        m_Character = _Character;
    }
 
};
 
CCharacter* QuestNpc::m_Character = NULL;
int            QuestNpc::m_QuestCount = NULL;
 
class OrcQuestNpc : public QuestNpc
{
private : // OrcQuest
    virtual void QuestShow() 
    { 
        if( !strcmp( m_Character->GetKind(), "오크" ) )
        {
            cout << "오크 퀘스트를 배분합니다." << endl;
        }
        else
        {
            ++m_QuestCount;
            m_pQuestNpc->QuestShow();
 
            switch(m_QuestCount)
            {
            case KIND_MAX_COUNT:
                QuestNpc::QuestShow();     
                break;
            }
        }
    }
};
 
class HummunQuestNpc : public QuestNpc
{
    virtual void QuestShow() // HummunQuest
    { 
        if( !strcmp( m_Character->GetKind(), "휴먼" ) )
        {
            cout << "휴먼 퀘스트를 배분합니다." << endl;
        }
        else
        {
            ++m_QuestCount;
            m_pQuestNpc->QuestShow();
 
            switch(m_QuestCount)
            {
            case KIND_MAX_COUNT:
                QuestNpc::QuestShow();     
                break;
            }
        }
    }    
};
 
class ElfQuestNpc : public QuestNpc
{
    virtual void QuestShow() // ElfQuest
    { 
        if( !strcmp( m_Character->GetKind(), "엘프" ) )
        {
            cout << "엘프 퀘스트를 배분합니다." << endl;
        }
        else
        {
            ++m_QuestCount;
            m_pQuestNpc->QuestShow();
 
            switch(m_QuestCount)
            {
            case KIND_MAX_COUNT:
                QuestNpc::QuestShow();     
                break;
            }
        }
    }    
};
 
// Chain of Resposibility.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
//
 
#include "stdafx.h"
#include "Chain of Resposibility.h"
 
 
int _tmain(int argc, _TCHAR* argv[])
{
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    //_CrtSetBreakAlloc(215);
#endif
 
    CCharacter* pOrc = new CCharacter("오크""전사");
    CCharacter* pElf = new CCharacter("엘프""궁수");
    CCharacter* pHummun = new CCharacter("휴먼""마법사");
    CCharacter* pNone = new CCharacter("하플링""마법사");
    
    QuestNpc* pOrcQuestNpc = new OrcQuestNpc;
    QuestNpc* pElfQuestNpc = new HummunQuestNpc;
    QuestNpc* pHummunQuestNpc = new ElfQuestNpc;
 
    pOrcQuestNpc->SetNextQuestNpc(pElfQuestNpc);
    pElfQuestNpc->SetNextQuestNpc(pHummunQuestNpc);
    pHummunQuestNpc->SetNextQuestNpc(pOrcQuestNpc);
 
    pOrcQuestNpc->SetPlayer(pElf);
    pOrcQuestNpc->QuestShow();
    pOrcQuestNpc->SetPlayer(pOrc);
    pOrcQuestNpc->QuestShow();
    pOrcQuestNpc->SetPlayer(pHummun);
    pOrcQuestNpc->QuestShow();
    pOrcQuestNpc->SetPlayer(pNone);
    pOrcQuestNpc->QuestShow();
 
    SAFE_DELETE(pOrc);
    SAFE_DELETE(pElf);
    SAFE_DELETE(pHummun);
    SAFE_DELETE(pNone);
 
    SAFE_DELETE(pOrcQuestNpc);
    SAFE_DELETE(pElfQuestNpc);
    SAFE_DELETE(pHummunQuestNpc);
 
    return 0;
}

 

결과 ----------------------------------------------------------------------------------------------- 

 

 

Posted by JJOREG

프록시 패턴 --------------------------------------------------------------------------------------------------

  하나의 객체는 내부적으로 다양한 맴버를 가지고 혹은 포인터를 가질때도 많습니다.

  혹은 하나의 거대한 이미지나 데이터를 사용하기 용이하게 하기 위한 객체로 디자인 되기도 합니다.

  하지만 실제 게임이나 프로그램을 보면 한 유저가 게임을 실행하고 게임내의 모든 데이터를 사용하는 경우는 거의 없습니다.

  온 지역을 돌아다니며 모든 몬스터를 만다고 모든 아이템을 한꺼번에 모두 가지고 있는 경우는 희귀한 편이고

  게임 디자인또한 그런식으로 되지 않습니다.

  대리자 패턴은 그런 경우 꼭 필요한 객체만을 생성하고 그 함수를 이용할수 있게 해주거나.

  가벼운 일은 가벼운 객체만 생성해서 해결하고 실제 아직 요청되지 않은 무거운 객체는 나중에 생성하게 하는 패턴입니다.

 

l        Remote Proxy로서의 역할. 원격의 객체에 대한 로컬의 대리자(local representative)를 제공하는데 쓰인다.
l        Virtual Proxy로서의 역할. 많은 비용이 요구되는 객체를 생성하는 경우에 사용된다. 앞서 컨텍스트 항목에서 설명한 경우가 이러한 적용의 예다.
l        Protection Proxy로서의 역할. 보호가 요구되는 객체 자체에 대한 접근을 통제하고 대리자를 통해 접근 가능한 정도만 노출시키고자 할 때 쓴다.
l        Smart Reference로서의 역할. 객체에 대한 단순한 접근 이외의 부가적인 작업을 수행할 필요가 있을 때 사용한다.

 

패턴적용 스토리 -----------------------------------------------------------------------------------------------

  이번에 적용되는 스토리는 다음과 같습니다.

  당신은 아이템 클래스의 정보와 랜더를 맡게 되었습니다.

  아이템의 기능은 크게 2가지 입니다.

  인벤창에 있을때 아이템에 대한 데이터를 보여준다.

  장착 했을때 캐릭터에게 3dmash 이미지를 띄워준다.

  아이템 인포는 매우 작은 작업니다.

  하지만 3가지 분류의 1000가지가 넘는 아이템이 있고 실제 그 아이템을 플레이어가 모두 소유하고 있지는 않기 때문에 필요할때만

  매쉬를 생성하고 마찬가지로 필요할 때만 아이템에 대한 정보를 로드하기로 했습니다.

 

uml -----------------------------------------------------------------------------------------------

 

 

보시면 알겠지만 플라이웨이트 패턴과 결합되어 있는 구조입니다.

대리 객체인 CItemProxy 클래스는 내부에 자신과 같이 CitemBase를 상속받고있는 CItem 클래스를 보유하고 있습니다.

내부적으로 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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
#pragma once
 
#include "include.h"
 
const int MaxItemName = 100;
 
const int ItemDataIndexMax = 10;
const int MashIndexMax = 10;
 
enum ITEMTYPE
{
    ITEMTYPE_ATT,
    ITEMTYPE_DEF,
    ITEMTYPE_ACC,
};
 
typedef struct Iteminfo
{
    char szItemName[MaxItemName];
    int iItemRenderIndex;
    int iItemType;
    int iItemOption;
 
    Iteminfo() {}
 
    Iteminfo(const char* _szItemName, const int& _iItemRenderIndex, const int& _ItemType, const int& _iItemOption)
    : iItemRenderIndex(_iItemRenderIndex) 
    , iItemType(_ItemType)
    , iItemOption(_iItemOption)
    { 
        strcpy_s(szItemName, _szItemName);
    }
 
}ITEMINFO, *PITEMINFO;
 
class Item3DMash
{
private:
    int MashIndex;
 
public:
    const int& GetMashIndex(void) {return MashIndex; }
 
public:
    void MashRender()
    { cout << MashIndex << "번 인덱스 매쉬 랜더" << endl; }
 
 
public:
    Item3DMash(const int _MashIndex) : MashIndex(_MashIndex) { cout << "매쉬 생성 완료" << endl; }
    ~Item3DMash() {}
};
 
 
Item3DMash* FindItemMashFile(const int& iKey)
{
    Item3DMash* pMash;
 
    if(iKey >= MashIndexMax)
    {
        return NULL;
    }
 
    pMash = new Item3DMash(iKey);
 
    return pMash;
}
 
class CFlyItemMash
{
private:
    map<int, Item3DMash*>    m_ProtoMash;
 
public:
    Item3DMash* FindMash(const int& iKey)
    {
        map<int, Item3DMash*>::iterator ItemMashIter = m_ProtoMash.find(iKey);
 
        if(ItemMashIter == m_ProtoMash.end())
        {
            return NULL;
        }
 
        return ItemMashIter->second;
    }
 
    bool MashInsert(Item3DMash* _pMash)
    {
        if(!_pMash)
        { 
            cout << "매쉬 데이터 정보 오류." << endl;
            return false;
        }
 
        map<int, Item3DMash*>::iterator ItemMashIter = m_ProtoMash.find(_pMash->GetMashIndex());
 
        if(ItemMashIter != m_ProtoMash.end())
        { 
            cout << "이미 로딩한 매쉬입니다." << endl;
            return false;
        }
 
        m_ProtoMash.insert(map<int, Item3DMash*>::value_type(_pMash->GetMashIndex(), _pMash));
        return true;
    }
 
    Item3DMash* GetMash(const int& iKey)
    {
        Item3DMash* pMash = FindMash(iKey);
 
        if(!pMash)
        {
            pMash = FindItemMashFile(iKey);
 
            if(MashInsert(pMash))
            { return pMash; }
            else
            { return NULL; }
        }
 
        return pMash;
    }
 
private:
    static CFlyItemMash* m_Inst;
 
public:
    static CFlyItemMash* GetInst()
    {
        if(m_Inst == NULL)
        { m_Inst = new CFlyItemMash(); }
        return m_Inst;
    }
 
    void DestroyInst() { SAFE_DELETE(m_Inst); }
 
 
private:
    CFlyItemMash(void) {}
public:
    ~CFlyItemMash(void) {SAFE_DELETE_MAP(m_ProtoMash);}
};
 
CFlyItemMash* CFlyItemMash::m_Inst = NULL;
 
PITEMINFO FindItemDataFile(const int& iKey)
{
    PITEMINFO pInfo = NULL;
 
    if(iKey >= ItemDataIndexMax)
    {
        cout << iKey << "키의 아이템정보 파일이 존재하지 않습니다." << endl;
        return NULL;
    }
 
    char szName[MaxItemName];
 
    sprintf_s(szName, "%dITEM", rand() % 10);
 
    pInfo = new Iteminfo(szName, rand() % 10, rand() % 10, rand() % 100);
 
    return pInfo;
}
 
class CFlyItemDataBase
{
private:
    map<int, PITEMINFO>    m_ProtoSkillData;
 
public:
 
    ITEMINFO* FindItemInfo(const int& iKey)
    {
        map<int, PITEMINFO>::iterator ItemInfoIter = m_ProtoSkillData.find(iKey);
 
        if(ItemInfoIter == m_ProtoSkillData.end())
        {
            return NULL;
        }
 
        return ItemInfoIter->second;
    }
 
    bool SkillDataInsert(PITEMINFO _Iteminfo)
    { 
        if(!_Iteminfo)
        { 
            cout << "아이템 데이터 정보 오류." << endl;
            return false;
        }
 
        map<int, PITEMINFO>::iterator ItemInfoIter = m_ProtoSkillData.find(_Iteminfo->iItemRenderIndex);
 
        if(ItemInfoIter != m_ProtoSkillData.end())
        { 
            cout << "입력하려는 아이템 정보가 이미 존재합니다." << endl;
            return false;
        }
 
        m_ProtoSkillData.insert(map<int, PITEMINFO>::value_type(_Iteminfo->iItemRenderIndex, _Iteminfo));
 
        return true;
    }
 
    const PITEMINFO GetSkillInfo(const int& iKey)
    {
        PITEMINFO pInfo = FindItemInfo(iKey);
 
        if(!pInfo)
        {
            pInfo = FindItemDataFile(iKey);
 
            if(SkillDataInsert(pInfo))
            { return pInfo; }
            else
            { return NULL; }
        }
 
        return pInfo;
    }
 
private:
    static CFlyItemDataBase* m_Inst;
 
public:
    static CFlyItemDataBase* GetInst()
    {
        if(m_Inst == NULL)
        { m_Inst = new CFlyItemDataBase(); }
        return m_Inst;
    }
 
    void DestroyInst() { SAFE_DELETE(m_Inst); }
 
private:
    CFlyItemDataBase(void) {}
public:
    virtual ~CFlyItemDataBase(void) {}
 
};
 
CFlyItemDataBase* CFlyItemDataBase::m_Inst = NULL;
 
class CItemBase
{
public:
    virtual void SkillInfoSetting(const ITEMTYPE& iType, const int& iKey) = 0;
    virtual void SKillInfoRender() = 0;
    virtual void ItemMashRender() = 0;
 
public:
    CItemBase() {}
    virtual ~CItemBase() {}
};
 
class CItem
    : public CItemBase
{
protected:
    Item3DMash*        m_pItemMash;
    PITEMINFO        m_pItemInfo;
 
public:
    virtual void SkillInfoSetting(const ITEMTYPE& iType, const int& iKey)
    { 
        m_pItemMash = CFlyItemMash::GetInst()->GetMash(iKey);
        m_pItemInfo = CFlyItemDataBase::GetInst()->GetSkillInfo(iKey);
    }
    virtual void SKillInfoRender()
    { 
        cout << "**** 아이템 정보 ****" << endl; 
    }
    virtual void ItemMashRender()
    { cout << "**** 아이템 매쉬랜더 ****" << endl; }
    
public:
    void SetItemInfo(const PITEMINFO& _pItemInfo)
    {
        m_pItemInfo = _pItemInfo;
    }
 
    void SetMash(Item3DMash* _pItemMash)
    {
        m_pItemMash = _pItemMash;
    }
 
public:
    CItem() : m_pItemMash(NULL), m_pItemInfo(NULL) {}
    virtual ~CItem() {}
};
 
class CAttItem
    : public CItem
{
public:
    virtual void SkillInfoSetting(const ITEMTYPE& iType, const int& iKey)
    {
        CItem::SkillInfoSetting(iType, iKey);
    }
 
    virtual void SKillInfoRender()
    {
        CItem::SKillInfoRender();
        if(m_pItemInfo)
        {
        cout << "무기 정보" << endl;
        cout << "이름" << m_pItemInfo->szItemName << " "  ;
        cout << "타입" << m_pItemInfo->iItemType << " " ;
        cout << "수치" << m_pItemInfo->iItemOption << endl;
        }
    }
 
    virtual void ItemMashRender()
    {
        CItem::ItemMashRender();
        cout << "무기 랜더 위치 설정" << endl;
        if(m_pItemMash)
            m_pItemMash->MashRender();
 
        cout << endl;
    }
 
public:
    CAttItem() {}
    virtual ~CAttItem() {}
};
 
class CDefItem
    : public CItem
{
public:
    virtual void SkillInfoSetting(const ITEMTYPE& iType, const int& iKey)
    {
        CItem::SkillInfoSetting(iType, iKey);
    }
 
    virtual void SKillInfoRender()
    {
        CItem::SKillInfoRender();
        if(m_pItemInfo)
        {
        cout << "방어구 정보" << endl;
        cout << "이름" << m_pItemInfo->szItemName << " "  ;
        cout << "타입" << m_pItemInfo->iItemType << " " ;
        cout << "수치" << m_pItemInfo->iItemOption << endl;
        }
    }
 
    virtual void ItemMashRender()
    {
        CItem::ItemMashRender();
        cout << "방어구 랜더 위치 설정" << endl;
        if(m_pItemMash)
        m_pItemMash->MashRender();
 
        cout << endl;
    }
 
public:
    CDefItem() {}
    virtual ~CDefItem() {}
};
 
class CAccItem
    : public CItem
{
public:
    virtual void SkillInfoSetting(const ITEMTYPE& iType, const int& iKey)
    {
        CItem::SkillInfoSetting(iType, iKey);
    }
 
    virtual void SKillInfoRender()
    {
        CItem::SKillInfoRender();
        if(m_pItemInfo)
        {
        cout << "방어구 정보" << endl;
        cout << "이름" << m_pItemInfo->szItemName << " "  ;
        cout << "타입" << m_pItemInfo->iItemType << " " ;
        cout << "수치" << m_pItemInfo->iItemOption << endl;
        }
    }
 
    virtual void ItemMashRender()
    {
        CItem::ItemMashRender();
        cout << "방어구 랜더 위치 설정" << endl;
        if(m_pItemMash)
            m_pItemMash->MashRender();
 
        cout << endl;
    }
 
public:
    CAccItem() {}
    virtual ~CAccItem() {}
};
 
class CItemProxy
    : public CItemBase
{
private:
    CItemBase*            m_Item;
 
public:
    virtual void SkillInfoSetting(const ITEMTYPE& iType, const int& iKey)
    {
        if(m_Item == NULL)
        {
            switch(iType)
            {
            case ITEMTYPE_ATT :
                m_Item = new CAttItem();
                break;
            case ITEMTYPE_DEF :
                m_Item = new CDefItem();
                break;
            case ITEMTYPE_ACC :
                m_Item = new CAccItem();
                break;
            }
        }
        m_Item->SkillInfoSetting(iType, iKey);
    }
 
    virtual void SKillInfoRender()
    {
        m_Item->SKillInfoRender();
    }
 
    virtual void ItemMashRender()
    {    
        m_Item->ItemMashRender();
    }
 
public:
    CItemProxy() : m_Item(NULL) {}
    virtual ~CItemProxy(void) {}
};
 
// Proxy.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
//
 
#include "stdafx.h"
#include "Proxy.h"
 
 
int _tmain(int argc, _TCHAR* argv[])
{
 
    CItemProxy* pProxyAtt = new CItemProxy;
 
    pProxyAtt->SkillInfoSetting(ITEMTYPE_ATT, 2);
 
    pProxyAtt->SKillInfoRender();
 
    pProxyAtt->ItemMashRender();
 
    CItemProxy* pProxyDef = new CItemProxy;
 
    pProxyDef->SkillInfoSetting(ITEMTYPE_DEF, 8);
 
    pProxyDef->SKillInfoRender();
 
    pProxyDef->ItemMashRender();
 
    CItemProxy* pProxyAcc = new CItemProxy;
 
    pProxyAcc->SkillInfoSetting(ITEMTYPE_ACC, 10);
 
    pProxyAcc->SKillInfoRender();
 
    pProxyAcc->ItemMashRender();
 
    SAFE_DELETE(pProxyAtt);
    SAFE_DELETE(pProxyDef);
    SAFE_DELETE(pProxyAcc);
 
    return 0;
}

 

 

Posted by JJOREG

플라이 웨이트 패턴 --------------------------------------------------------------------------------------------------

  일반적으로 포인터나 주소값은 대부분 같은 것을 참조할 때가 많습니다.

  하지만 대부분의 객체가 이러한 포인터 값을 다수 가지고 있다면 메모리에 대한 부담이 커질수가 있습니다.

  그래서 하나의 자료구조에 포인터를 모아놓고 사용해야할 객체들이 그 정보들을 전역변수처럼 돌려쓰는 것이

  대표적인 것이 이미지에 대한 정보 입니다. 완전히 같은 이미지를 사용하는 2개의 객체가 있을때.

  굳이 2개의 이미지를 로딩하는 것이 아니라. 1개만 로딩한후 그것을 돌려쓰면 됩니다.


 

패턴적용 스토리 -----------------------------------------------------------------------------------------------

  당신에게 오브젝트 랜더에에 대한 임무가 내려졌습니다.

  오브젝트 랜더를 위해서는 이미지가 필요한데.

  각 오브젝트마다 이미지를 로딩해 봤더니 이미지에 대한 데이터부담이 너무 커졌습니다.

  그래서 당신은 플라이웨이트 패턴을 사용하여 만약 오브젝트들이 같은 이미지를 랜더한다면 그 이미지를 한번만 로딩하기로 결정했습니다.

 

uml -----------------------------------------------------------------------------------------------

 

 

플라이 웨이트패턴을 보면 오브젝트에서는 CFlyTexture에 있는 stl자료구조 안에 담긴 텍스처의 포인터를 가져와서 랜더를 합니다.

즉 프로토타입처럼 하나의 이미지를 다수의 오브젝트가 공유하여 사용하는 패턴입니다.

 

코드 -----------------------------------------------------------------------------------------------

 

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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#pragma once
#include "include.h"
 
enum TEXTYPE
{
    TEXTYPE_SINGLE,
    TEXTYPE_MULTI,
};
 
enum FILENAME_COUNT
{
    FILENAME_COUNT_MAX = 100,
};
 
class Texture
{
protected:
    char    szName[FILENAME_COUNT_MAX];
 
public:
    virtual void LoadTexture(const char* pfilename) = 0;
    virtual void GetTexture(const int _iKey, const int TexCount = 0) = 0;
    virtual void Render(void) = 0;
};
 
class SingleTexture
    : public Texture
{
public:
    virtual void LoadTexture(const char* pfilename)
    {
        cout << pfilename << "텍스처 로딩" <<endl;
        strcpy_s(szName, pfilename);
    }
    virtual void GetTexture(const int _iKey, const int _TexCount = 0)
    {
        cout << szName << "텍스처 사용" <<endl;
    }
    virtual void Render(void)
    {
        cout << szName << "랜더" <<endl;
    }
 
public:
    SingleTexture(void) {}
    virtual ~SingleTexture(void) {}
};
 
class MultiTexture
    : public Texture
{
public:
    virtual void LoadTexture(const char* _pfilename)
    {
        cout << _pfilename << "폴더에 있는 모든 텍스처 로딩" <<endl;
        strcpy_s(szName, _pfilename);
    }
    virtual void GetTexture(const int _iKey, const int _TexCount)
    {
        cout << szName << " " << _TexCount << "텍스처 사용" <<endl;
    }
    virtual void Render(void)
    {
        cout << szName << " " << "애니메이션 랜더" <<endl;
    }
 
public:
    MultiTexture(void) {}
    virtual ~MultiTexture(void) {}
};
 
class CFlyTexture
{
private:
    map<const int, Texture*> m_mapTexture;
 
public:
    bool InsertTexture(const char* pfilename, const int iKey, const TEXTYPE& _eTexType)
    {
        map<const int, Texture*>::iterator Iter = m_mapTexture.find(iKey);
 
        if(Iter != m_mapTexture.end())
        { cout << "이미 추가된 텍스처 입니다" << endl; return true; }
 
        Texture* pTex;
 
        switch(_eTexType)
        {
        case TEXTYPE_SINGLE:
            {
                pTex = new SingleTexture;
                pTex->LoadTexture(pfilename);
                break;
            }
 
        case TEXTYPE_MULTI:
            {
                pTex = new MultiTexture;
                pTex->LoadTexture(pfilename);
                break;
            }
        }
 
        m_mapTexture.insert( map<const int, Texture*>::value_type(iKey, pTex) );
 
        return false;
    }
 
    void Init(void)
    {
        InsertTexture("지형지물0", 0, TEXTYPE_SINGLE);
        InsertTexture("지형지물1", 1, TEXTYPE_SINGLE);
        InsertTexture("지형지물2", 2, TEXTYPE_SINGLE);
        InsertTexture("지형지물3", 3, TEXTYPE_SINGLE);
        InsertTexture("몬스터1",  4, TEXTYPE_MULTI);
        InsertTexture("몬스터2",  5, TEXTYPE_MULTI);
        InsertTexture("플레이어", 6, TEXTYPE_MULTI);
 
        cout << endl;
    }
 
    Texture* GetTexture(const int iKey, const int TexCount = 0)
    {
        map<const int, Texture*>::iterator Iter = m_mapTexture.find(iKey);
 
        if(Iter == m_mapTexture.end())
        {
            cout << "텍스처가 없습니다" << endl;
            return NULL;
        }
 
        return Iter->second;
    }
 
    void Release(void)
    {
        map<const int, Texture*>::iterator Iter;
        for(Iter = m_mapTexture.begin(); Iter != m_mapTexture.end() ; ++Iter)
        {
            SAFE_DELETE(Iter->second);
        }
        m_mapTexture.clear();
    }
 
public:
    static CFlyTexture* m_Inst;
 
    static inline CFlyTexture* GetInst(void)
    {
        if(m_Inst == NULL)
            m_Inst = new CFlyTexture();
        return m_Inst;
    }
 
    static void DestroyInst(void)
    {
        SAFE_DELETE(m_Inst);
    }
 
private:
    CFlyTexture(void) {}
public:
    ~CFlyTexture(void) { Release(); }
};
 
CFlyTexture* CFlyTexture::m_Inst = NULL;
 
class CObject
{
private:
    int        TexNum;
 
public:
    void Render(void)
    {
        Texture* pTex = CFlyTexture::GetInst()->GetTexture(TexNum);
 
        if(pTex)
            pTex->Render();
    }
 
public:
    CObject(int _Tex) {TexNum = _Tex;}
    ~CObject() {}
};
 
// Flyweight.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
//
 
#include "stdafx.h"
#include "Flyweight.h"
 
 
int _tmain(int argc, _TCHAR* argv[])
{
    CFlyTexture::GetInst()->Init();
 
    CObject* pTerrain0 = new CObject(0);
    CObject* pTerrain1 = new CObject(0);
    CObject* pTerrain2 = new CObject(1);
    CObject* pTerrain3 = new CObject(1);
    CObject* pMonster1 = new CObject(5);
    CObject* pMonster2 = new CObject(5);
    CObject* pMonster3 = new CObject(6);
    CObject* pPlayer   = new CObject(6);
 
    pTerrain0->Render();
    pTerrain1->Render();
    pTerrain2->Render();
    pTerrain3->Render();
    pMonster1->Render();
    pMonster2->Render();
    pMonster3->Render();
    pPlayer->Render();
 
    SAFE_DELETE(pTerrain0);
    SAFE_DELETE(pTerrain1);
    SAFE_DELETE(pTerrain2);
    SAFE_DELETE(pTerrain3);
    SAFE_DELETE(pMonster1);
    SAFE_DELETE(pMonster2);
    SAFE_DELETE(pMonster3);
    SAFE_DELETE(pPlayer);
 
    CFlyTexture::DestroyInst();
 
    return 0;
}

결과 -----------------------------------------------------------------------------------------------

 

Posted by JJOREG


퍼사드 패턴 --------------------------------------------------------------------------------------------------

  퍼사드 패턴이란 복잡하에 얽혀있는 서브클래스들과 그 클래스가 모여서 이루려는 목적을

  클라이언트가 아닌 하나의 클래스에서 종합하는 패턴을 의미한다.

  무슨 의미냐. 게임적으로 생각해보면 MMORPG게임에서 경매장이라는 기능을 보자.

  이 경매장 클래스 내부에서 모든 기능을 가질수는 없기 때문에(혹은 경매장에서 사용하는 기능을 다른 기능에서 사용할수 있으니)

  클래스나 서브시스템으로 분리되어 있을 것입니다.


1. 검색 기능(클래스 또는 함수)

2. 플레이어 금액정산 기능(클래스 또는 함수)

3. 상품발송 기능(클래스 또는 함수)

4. 거래량 판단기능(클래스 또는 함수)

5. 경매장 랜더 기능(클래스 또는 함수)


  위의 기능들이 클래스 안에 들어있다고 생각해봅시다. 클라이언트에서 경매장의 온전한 기능을 사용하려면 저 기능들을 잘 조합해서 사용해야 할 것입니다.

  퍼사드 패턴은 이러한 기능들을 하나의 클래스 안에 묶어서 외부에서 그 하나의 클래스를 통해서 저 기능들을 종합하여 사용하게 하는 패턴을 의미합니다.


패턴적용 스토리 -----------------------------------------------------------------------------------------------

  당신은 턴제게임의 행동패턴을 맡게 되었습니다.

  당신에게 요구된 사항과 제공되는 서브시스템들은 다음과 같습니다.

  1. 캐릭터 클래스

  2. 캐릭터의 수만큼 캐릭터에게 행동력을 부여하는 기능

  3. 부여된 행동력만큼 캐릭터들을 정렬시켜주는 기능(행동력이 높은 순서대로, 행동력이 같다면 캐릭터 인덱스가 낮은 순서대로 행동한다)

  4. 정렬된 캐릭터의 액션을 동작시키는 기능


  이 기능들을 조합하여 각 캐릭터의 행동을 하게 만들어야 합니다.


uml -----------------------------------------------------------------------------------------------




포면 알겠지만 액션퍼사드 클래스는 각 클래스와 기능들을 내부에서 종합하게 되어 외부에서 캐릭터를 캐릭터를 정렬하고 캐릭터가 행동하게 하는 기능은 모두 액션퍼사드 클래스를 가지게 됩니다. 즉 외부로 드러나는 인터페이스와 기능을 하나의 외부 인터페이스에 모아 놓는 패턴입니다.


코드 -------------------------------------------------------------------------------------------------------------------


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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
#pragma once
 
#include "include.h"
 
enum CHARACTER_ACTION
{
    CHARACTER_ACTION_RELAX,
    CHARACTER_ACTION_ATT,
    CHARACTER_ACTION_DEF,
    CHARACTER_ACTION_MOVE,
    CHARACTER_ACTION_COUNT,
};
 
typedef struct _tagCharacterInfo
{
    int CharacterIndex;
    int ActionPoint;
    int ActionType;
    int Speed;
    int Move;
    int Att;
    int Def;
    int Relax;
 
    void Setting( const _tagCharacterInfo& _CharacterInfo ) { *this = _CharacterInfo; }
 
    _tagCharacterInfo(void)  { }
    _tagCharacterInfo(int _CharacterIndex, int _ActionPoint, int _ActionType, int _Speed,  int _Move, int _Att, int _Def, int _Relax)
        : CharacterIndex(_CharacterIndex), ActionPoint(_ActionPoint), ActionType(_ActionType), Speed(_Speed)
        , Move(_Move), Att(_Att), Def(_Def), Relax(_Relax) { }
    _tagCharacterInfo( const _tagCharacterInfo& _CharacterInfo ) { *this = _CharacterInfo; }
 
}CHARACTERINFO, *PCHARACTERINFO;
 
class CCharacter
{
private:
    CHARACTERINFO    m_CharacterInfo;
 
public// Get
    const CHARACTERINFO& GetCharacterInfo(voidconst 
    { return m_CharacterInfo; }
 
public// Set
    void SetUserInput(const int& _CharacterAct)
    { m_CharacterInfo.ActionType = _CharacterAct; }
    void SetActionPoint(const int& _ActionPotin)
    { m_CharacterInfo.ActionPoint = _ActionPotin; }
 
public:
    void Action(void)
    {
        switch(m_CharacterInfo.ActionType)
        {
        case CHARACTER_ACTION_RELAX :
            Relax();
            break
        case CHARACTER_ACTION_ATT :
            Att();
            break
        case CHARACTER_ACTION_DEF :
            Def();
            break
        case CHARACTER_ACTION_MOVE :
            Move(); 
            break
        }
    }
 
    void ActionPointRender(void
    {
        cout << "행동력" << m_CharacterInfo.ActionPoint << "**********" <<endl;
    }
 
    void Relax(void
    {    
        ActionPointRender();
        cout << m_CharacterInfo.CharacterIndex << "번 캐릭터는 휴식한다" << endl; 
        cout << m_CharacterInfo.Relax << "만큼 회복했다!" << endl; 
    }
    void Att(void
    {    
        ActionPointRender();
        cout << m_CharacterInfo.CharacterIndex << "번 캐릭터는 공격한다" << endl; 
        cout << m_CharacterInfo.Att << "만큼 공격했다!" << endl; 
    }
    void Def(void
    {    
        ActionPointRender();
        cout << m_CharacterInfo.CharacterIndex << "번 캐릭터는 방어한다" << endl; 
        cout << m_CharacterInfo.Def << "만큼 방어했다!" << endl; 
    }
    void Move(void
    {    
        ActionPointRender();
        cout << m_CharacterInfo.CharacterIndex << "번 캐릭터는 이동한다" << endl; 
        cout << m_CharacterInfo.Move << "만큼 이동했다!" << endl; 
    }
 
public:
    CCharacter(void) {}
    CCharacter(const CHARACTERINFO& _CharacterInfo) { m_CharacterInfo = _CharacterInfo; }
    ~CCharacter(void) {}
};
 
class CUserInputQueue
{
private:
    queue<int> UserInput;
 
public:
    void SetUserInput(const int& _MaxCharacter)
    {
        for(int i = 0 ; i < _MaxCharacter ; ++i)
        {
            UserInput.push(rand() % CHARACTER_ACTION_COUNT);
        }
    }
 
    void SetUserInputToCharacter(CCharacter* const _Character)
    {
        _Character->SetUserInput(UserInput.front());
        UserInput.pop();
    }
 
 
public:
    CUserInputQueue(void) {}
    ~CUserInputQueue(void) {}
};
 
class CCharacterSort
{
private:
    map<int, map<int, CCharacter*>> m_mapCharacter;
 
public:
    void PushCharacter(CCharacter* const _Character)
    {
        map<int, map<int, CCharacter*>>::iterator FirIter = m_mapCharacter.find(_Character->GetCharacterInfo().ActionPoint);
 
        if(FirIter == m_mapCharacter.end())
        {
            map<int, CCharacter*> _TempMap;
 
            _TempMap.insert(map<int, CCharacter*>::value_type(_Character->GetCharacterInfo().CharacterIndex, _Character));
 
            m_mapCharacter.insert(map<int, map<int, CCharacter*>>::value_type(
                _Character->GetCharacterInfo().ActionPoint
                ,_TempMap));
        }
        else
        {
            FirIter->second.insert(map<int, CCharacter*>::value_type(_Character->GetCharacterInfo().CharacterIndex, _Character));
        }
    }
 
    void ActionPlayer(void)
    {
        if(!m_mapCharacter.empty())
        {
            map<int, map<int, CCharacter*>>::reverse_iterator reFirIter;
 
            map<int, CCharacter*>::iterator SecIter;
 
            for(reFirIter = m_mapCharacter.rbegin() ; reFirIter != m_mapCharacter.rend() ; ++reFirIter)
            {
                for( SecIter = reFirIter->second.begin() ; SecIter != reFirIter->second.end() ; ++SecIter)
                {
                    SecIter->second->Action();
                }
            }
        }
    }
 
public:
    CCharacterSort(void) {}
    ~CCharacterSort(void) {}
};
 
class CActionFacade
{
private:
    list<CCharacter*> m_CharacterList;
 
public:
    void PushPlayer(CCharacter* const _Character)
    { 
        m_CharacterList.push_back(_Character); 
    }
 
    void Action(void)
    {
        CUserInputQueue _InputQueue;
        _InputQueue.SetUserInput(m_CharacterList.size());
 
        CCharacterSort _CharacterSort;
 
        for(list<CCharacter*>::iterator Iter = m_CharacterList.begin(); Iter != m_CharacterList.end() ; ++Iter)
        {
            (*Iter)->SetActionPoint(rand() % (*Iter)->GetCharacterInfo().Speed);
            _InputQueue.SetUserInputToCharacter(*Iter);
            _CharacterSort.PushCharacter(*Iter);
        }
 
        _CharacterSort.ActionPlayer();
    }
 
    void Release(void)
    {
        if(!m_CharacterList.empty())
        {
            for(list<CCharacter*>::iterator Iter = m_CharacterList.begin(); Iter != m_CharacterList.end() ; ++Iter)
            {
                SAFE_DELETE(*Iter);
            }
            m_CharacterList.clear();
        }
    }
 
 
public:
    CActionFacade(void) {}
    ~CActionFacade(void) {}
};
 
// facade.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
//
 
#include "stdafx.h"
#include "Facade.h"
 
int _tmain(int argc, _TCHAR* argv[])
{
 
    CActionFacade Facade;
 
    for(int i = 0 ; i < 5 ; ++i)
    { Facade.PushPlayer(new CCharacter(CHARACTERINFO(i,0,0,rand() % 100 + 1,0,0,0,0))); }
 
    Facade.Action();
 
    Facade.Release();
 
    return 0;
}
 
 


실행 결과 -------------------------------------------------------------------------------------------------------------------------------



Posted by JJOREG
데코레이터 패턴 --------------------------------------------------------------------------------------------------

  객체지향 프로그래밍은 클래스를 통해서 만들어진 객체들의 기능을 통해서 만들어 진다.

  이때 객체들의 기능은 클래스 단계에서 정적으로 고정된 경우가 많다.

  데코레이터 패턴이란 이러한 기존에 구성된 정적인 객체의 기능을 동적으로 할당하고 삭제하는데 그 의미가 있다.

  이러한 경우는 일반적으로 캐릭터의 모션이 완전히 바뀌어야 하거나 혹은 전혀 다른 패시브 스킬들을 적용시켜야 할때 필요하다.

  즉 내부의 조건문을 통한 기능의 변화가 아닌 객체 자체를 동적으로 기능변경 시켜 코드량을 줄이고 새로운 패턴을 추가하는 것이다.


패턴적용 스토리 -----------------------------------------------------------------------------------------------

  당신은 액션 게임을 만들고 있습니다. 모든 플레이어는 기본공격을 가지는데 당신은 그에 대한 디자인을 맡았습니다.

  1모션 -> 2 모션 -> 3모션 을 사용하면 다음 모션을 사용하고 다음 모션을 사용하는 식입니다.

  모든 플레이어는 3개의 모션을 가지며 당신은 그 모션과 특성들을 잘 디자인하라는 명령을 받았습니다.

  회사에서 원하는 조건은 다음과 같습니다.


  1. 플레이어는 최대 3연속 연속기를 사용한다.

  2. 이 모션들은 세팅에 따라서 언제든지 변할 수 있다.

  3. 최대 3개의 모션이기는 하지만 하나의 모션만 가질수도 2개의 모션만 가질수도 있게 디자인해야 한다.

  4. 기본 동작은 전투 준비 모션이다.


  제가 감안해야할 사항은 다음과 같았습니다.

  1. 만약 플레이어에게 3개의 공격동작이 있다면 언제든지 중간과정에서 추가가 가능해야한다.

  2. 기존에 모션이 세팅되어 있다고 하더라도 그 모션을 언제든지 교체할수 있어야 한다.


uml -----------------------------------------------------------------------------------------------



만약 최대 3개의 모션이 아니라 몇개든 추가될수 있다고 한다면 모션을 STL로 관리할 수도 있을 것이다.



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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
#pragma once
 
#include "include.h"
 
enum MOTIONQUEUE
{
    MOTIONQUEUE_1,
    MOTIONQUEUE_2,
    MOTIONQUEUE_3,
};
 
enum PLAYERMOTION
{
    PLAYERMOTION_NONE,
    PLAYERMOTION_UPSWING,
    PLAYERMOTION_DOWNSWING,
    PLAYERMOTION_SIDESWING,
    PLAYERMOTION_PIERCE,
};
 
class WeaponMotion
{
public:
    virtual void AttMotion(void) = 0;
    virtual void SetMotion(WeaponMotion* _PlayerMotion) = 0;
 
public:
    WeaponMotion(void) {}
    virtual ~WeaponMotion(void) {}
};
 
class DecoratorMotion
    : public WeaponMotion
{
private:
    WeaponMotion* m_PlayerMotion;
 
public:
    virtual void AttMotion(void)
    {
        if(m_PlayerMotion != NULL)
            m_PlayerMotion->AttMotion();
    }
 
    virtual void SetMotion(WeaponMotion* _PlayerMotion)
    {
        m_PlayerMotion = _PlayerMotion;
    }
 
public:
    DecoratorMotion(void) : m_PlayerMotion(NULL) {}
    DecoratorMotion(WeaponMotion* _PlayerMotion) : m_PlayerMotion(NULL) { m_PlayerMotion = _PlayerMotion; }
    virtual ~DecoratorMotion(void) {}
};
 
class FightReady
    : public DecoratorMotion
{
public:
    void AttMotion(void)
    {
        cout << "전투준비!" << endl;
        DecoratorMotion::AttMotion();
    }
 
    void SetMotion(WeaponMotion* _PlayerMotion)
    { DecoratorMotion::SetMotion(_PlayerMotion); }
 
public:
    FightReady(void) {}
    FightReady(WeaponMotion* _PlayerMotion) : DecoratorMotion(_PlayerMotion) { }
    virtual ~FightReady(void) {}
};
 
class UpSwing
    : public DecoratorMotion
{
public:
    void AttMotion(void)
    {
        cout << "위로 올려벤다" << endl;
        DecoratorMotion::AttMotion();
    }
 
    void SetMotion(WeaponMotion* _PlayerMotion)
    { DecoratorMotion::SetMotion(_PlayerMotion); }
 
public:
    UpSwing(void) {}
    UpSwing(WeaponMotion* _PlayerMotion) : DecoratorMotion(_PlayerMotion) { }
    virtual ~UpSwing(void) {}
};
 
class DownSwing
    : public DecoratorMotion
{
public:
    void AttMotion(void)
    {
        cout << "아래로 내려친다" << endl;
        DecoratorMotion::AttMotion();
    }
 
    void SetMotion(WeaponMotion* _PlayerMotion)
    { DecoratorMotion::SetMotion(_PlayerMotion); }
 
public:
    DownSwing(void){}
    DownSwing(WeaponMotion* _PlayerMotion) : DecoratorMotion(_PlayerMotion) { }
    virtual ~DownSwing(void){}
};
 
class SideSwing
    : public DecoratorMotion
{
public:
    void AttMotion(void)
    {
        cout << "측면으로 베어낸다" << endl;
        DecoratorMotion::AttMotion();
    }
 
    void SetMotion(WeaponMotion* _PlayerMotion)
    { DecoratorMotion::SetMotion(_PlayerMotion); }
 
public:
    SideSwing(void) {}
    SideSwing(WeaponMotion* _PlayerMotion) : DecoratorMotion(_PlayerMotion) { }
    virtual ~SideSwing(void) {}
};
 
class Pierce
    : public DecoratorMotion
{
public:
    void AttMotion(void)
    {
        cout << "찌른다!" << endl;
        DecoratorMotion::AttMotion();
    }
 
    void SetMotion(WeaponMotion* _PlayerMotion)
    { DecoratorMotion::SetMotion(_PlayerMotion); }
 
public:
    Pierce(void) {}
    Pierce(WeaponMotion* _PlayerMotion) : DecoratorMotion(_PlayerMotion) { }
    virtual ~Pierce(void) {}
};
 
class CPlayer
{
private:
    WeaponMotion*        MotionReady;
    WeaponMotion*        Motion1;
    WeaponMotion*        Motion2;
    WeaponMotion*        Motion3;
 
public:
    void SetMotion(const PLAYERMOTION& _AttMotionType, const MOTIONQUEUE& MotionNum)
    {
        switch(MotionNum)
        {
        case MOTIONQUEUE_1:
            CreMotion(_AttMotionType, &Motion1);
            if(MotionReady != NULL)
            { MotionReady->SetMotion(Motion1); }
            else
            { MotionReady->SetMotion(NULL); }
            break;
        case MOTIONQUEUE_2:
            CreMotion(_AttMotionType, &Motion2);
            if(Motion1 != NULL)
            { Motion1->SetMotion(Motion2); }
            else
            { MotionReady->SetMotion(NULL); }
            break;
        case MOTIONQUEUE_3:
            CreMotion(_AttMotionType, &Motion3);
            if(Motion2 != NULL)
            { Motion2->SetMotion(Motion3); }
            else
            { MotionReady->SetMotion(NULL); }
            break;
        }
    }
 
    void CreMotion(const PLAYERMOTION& _AttMotionType, WeaponMotion** _PlayerMotion)
    {
 
        SAFE_DELETE(*_PlayerMotion);
 
        switch(_AttMotionType)
        {
        case PLAYERMOTION_NONE:
            break;
        case PLAYERMOTION_UPSWING:
            *_PlayerMotion = new UpSwing();
            break;
        case PLAYERMOTION_DOWNSWING:
            *_PlayerMotion = new DownSwing();
            break;
        case PLAYERMOTION_SIDESWING:
            *_PlayerMotion = new SideSwing();
            break;
        case PLAYERMOTION_PIERCE:
            *_PlayerMotion = new Pierce();
            break;
        }
    }
 
    void Attact(void)
    {
        MotionReady->AttMotion();
        cout << endl;
    }
 
public:
    CPlayer(void)
    : MotionReady(NULL)
    , Motion1(NULL)
    , Motion2(NULL)
    , Motion3(NULL)
    {
        MotionReady = new FightReady();
        MotionReady->SetMotion(NULL);
    }
    ~CPlayer(void
    {
        SAFE_DELETE(MotionReady);
        SAFE_DELETE(Motion1);
        SAFE_DELETE(Motion2);
        SAFE_DELETE(Motion3);
    }
};
 
int _tmain(int argc, _TCHAR* argv[])
{
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    //_CrtSetBreakAlloc(219);
#endif
 
    CPlayer* Player = new CPlayer();
 
    Player->SetMotion(PLAYERMOTION_UPSWING, MOTIONQUEUE_1);
    Player->SetMotion(PLAYERMOTION_PIERCE, MOTIONQUEUE_2);
 
    Player->Attact();
 
    Player->SetMotion(PLAYERMOTION_PIERCE, MOTIONQUEUE_1);
    Player->SetMotion(PLAYERMOTION_SIDESWING, MOTIONQUEUE_2);
    Player->SetMotion(PLAYERMOTION_PIERCE, MOTIONQUEUE_3);
 
    Player->Attact();
 
    Player->SetMotion(PLAYERMOTION_NONE, MOTIONQUEUE_1);
    Player->SetMotion(PLAYERMOTION_NONE, MOTIONQUEUE_2);
    Player->SetMotion(PLAYERMOTION_NONE, MOTIONQUEUE_3);
 
    Player->Attact();
 
    SAFE_DELETE(Player);
 
    return 0;
}
 
 




Posted by JJOREG

컴포지트패턴 --------------------------------------------------------------------------------------------------

  클래스를 사용할때 우리는 대부분 다형성을 기반으로 클래스를 디자인한다.

  객체를 생성하고 관리하려면 먼저 그 객체의 자료형이 클래스가 정의되어야 하는데.

  어떤때는 여러개의 틀을 하나로 모아서 사용해야할 경우가 존재한다.

  즉 하나의 클래스에 상속을 받는 부분부분을 모아서 새로운 틀을 만들어야하는 경우가 존재한다.

  이 경우 이 객체를 복합객체(composite object) 혹은 복합 클래스(composite class)라고 한다.


패턴적용 스토리 -----------------------------------------------------------------------------------------------

  당신은 메카닉 액션 게임을 만들게 되었다. 메카닉 액션게임에서 공격에 사용되는 탄환을 디자인하게 되었다.

  그런데 전탄발사라고 하는 새로운 기능을 만들게 되었다.

  기존의 만들어진 탄환들을 모아서 발사한다.

  그래서 부분이면서 전체가 될 포함할 수 있는 컴포지트 패턴을 사용하기로 했다.


uml -----------------------------------------------------------------------------------------------

보면 알겠지만 전탄발사는 Arms를 포함하면서도 Arms에 속해있다.

또한 내부에서 stl List를 통해서 Arms를 다수 포함할수 있는 구조이다.

(굳이 이런 구조가 아니어도 된다. Arms를 2개 이상 가지고 있어도 충분하다.)

또한 프로토타입 패턴이 섞여있는데 각 객체는 프로토타입에 의해서 생성된다.


코드 -----------------------------------------------------------------------------------------------


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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
#pragma once
#include "include.h"
 
typedef struct _tagBulletInfo
{
    int iBulletType;
    int    iBulletSpeed;
    int    iBulletDamage;
 
    _tagBulletInfo(void)
    :iBulletType(0), iBulletSpeed(0), iBulletDamage(0) { }
 
    _tagBulletInfo(const int _Type, const int _Speed, const int _Damage)
    :iBulletType(_Type), iBulletSpeed(_Speed), iBulletDamage(_Damage) { }
 
}BULLETINFO, *PBULLETINFO;
 
class CArms
{
protected:
    BULLETINFO    m_BulletInfo;
 
public:
    virtual void AddArms(CArms* const _Arms) { }
 
public// setting
    virtual void BulletSetting(const BULLETINFO& _BulletInfo) = 0;
 
public// progress
    virtual void ArmsFire(void)
    {
        cout << "타입 :" << m_BulletInfo.iBulletType 
             << "스피드 :" << m_BulletInfo.iBulletSpeed 
             << "위력 :" << m_BulletInfo.iBulletDamage 
             << "무기준비 완료" << endl; 
    }
 
public// progress
    virtual CArms* clone(void) = 0;
 
public:
    CArms(void) {}
    CArms(const BULLETINFO& _BulletInfo) { m_BulletInfo = _BulletInfo; }
    CArms(const CArms& _Bullet) { *this = _Bullet; }
    virtual ~CArms(void) {}
};
 
 
class CVulcan
    : public CArms
{
public:
    virtual void BulletSetting(const BULLETINFO& _BulletInfo)
    { m_BulletInfo = _BulletInfo; }
 
    virtual void ArmsFire(void)
    { 
        CArms::ArmsFire();
        cout << "발칸을 발사했다!!!" << endl; 
    }
 
    virtual CArms* clone(void)
    { return new CVulcan(*this); }
 
public:
    CVulcan(void) {}
    CVulcan(const BULLETINFO& _BulletInfo) { m_BulletInfo = _BulletInfo; }
    CVulcan(const CVulcan& _Vulcan) { *this = _Vulcan; }
    virtual ~CVulcan(void) {}
};
 
class CPistol
    : public CArms
{
public:
    virtual void BulletSetting(const BULLETINFO& _BulletInfo)
    { m_BulletInfo = _BulletInfo; }
 
    virtual void ArmsFire(void)
    { 
        CArms::ArmsFire();
        cout << "권총을 발사했다!!!" << endl; 
    }
 
    virtual CArms* clone(void)
    { return new CPistol(*this); }
 
public:
    CPistol(void) {}
    CPistol(const BULLETINFO& _BulletInfo) { m_BulletInfo = _BulletInfo; }
    CPistol(const CPistol& _Pistol) { *this = _Pistol; }
    virtual ~CPistol(void) {}
};
 
 
class CRocket
    : public CArms
{
public:
    virtual void BulletSetting(const BULLETINFO& _BulletInfo)
    { m_BulletInfo = _BulletInfo; }
 
    virtual void ArmsFire(void)
    { 
        CArms::ArmsFire();
        cout << "로켓을 발사했다!!!" << endl; 
    }
 
    virtual CArms* clone(void)
    { return new CRocket(*this); }
 
public:
    CRocket(void) {}
    CRocket(const BULLETINFO& _BulletInfo) { m_BulletInfo = _BulletInfo; }
    CRocket(const CRocket& _Rocket) { *this = _Rocket; }
    virtual ~CRocket(void) {}
};
 
class CAllArmsFire
    : public CArms
{
private:
    list<CArms*>    m_ArmsList;
 
public:
    virtual void AddArms(CArms* const _Arms) { m_ArmsList.push_back(_Arms); }
 
public:
    virtual void BulletSetting(const BULLETINFO& _BulletInfo) {}
 
public
    virtual void ArmsFire(void
    {
        list<CArms*>::iterator ArmsIter = m_ArmsList.begin();
 
        cout << endl;
        cout << "전탄 발사!!!!" << endl;
 
        while(ArmsIter != m_ArmsList.end())
        { 
            (*ArmsIter)->ArmsFire(); 
            ++ArmsIter;
        }
    }
 
public
    virtual CArms* clone(void
    {
        CArms* pArms = new CAllArmsFire();
    
        list<CArms*>::iterator ArmsIter = m_ArmsList.begin();
 
        while(ArmsIter != m_ArmsList.end())
        {
            pArms->AddArms((*ArmsIter)->clone());
            ++ArmsIter;
        }
 
        return pArms;
    }
 
public:
    CAllArmsFire(void) {}
    CAllArmsFire(const CAllArmsFire& _AllArmsShot) { *this = _AllArmsShot; }
    virtual ~CAllArmsFire(void
    {
        list<CArms*>::iterator ArmsIter = m_ArmsList.begin();
 
        while(ArmsIter != m_ArmsList.end())
        {
            SAFE_DELETE((*ArmsIter));
            ++ArmsIter;
        }
        m_ArmsList.clear();
    }
};
 
class CArmsPoroto
{
private:
    map<string, CArms*>    m_ArmsProtoMap;
 
public:
    void InitArmsProto(void)
    {
        CArms* pArms = NULL;
        CArms* pAllFire = new CAllArmsFire;
 
        pArms = new CVulcan();
        pArms->BulletSetting(BULLETINFO(0, 10, 10));
        m_ArmsProtoMap.insert(map<string, CArms*>::value_type("CVulcan", pArms));
        pAllFire->AddArms(pArms->clone());
 
        pArms = new CPistol();
        pArms->BulletSetting(BULLETINFO(1, 15, 10));
        m_ArmsProtoMap.insert(map<string, CArms*>::value_type("CPistol", pArms));
        pAllFire->AddArms(pArms->clone());
 
        pArms = new CRocket();
        pArms->BulletSetting(BULLETINFO(2, 5, 20));
        m_ArmsProtoMap.insert(map<string, CArms*>::value_type("CRocket", pArms));
        pAllFire->AddArms(pArms->clone());
 
        m_ArmsProtoMap.insert(map<string, CArms*>::value_type("CAllArmsFire", pAllFire));
    }
 
public:
    CArms* GetCloneArms(const string& _ProtoKey)
    {
        map<string, CArms*>::iterator ProtoIter = m_ArmsProtoMap.find(_ProtoKey);
 
        if(ProtoIter == m_ArmsProtoMap.end())
            return NULL;
 
        return ProtoIter->second->clone();
    }
 
public:
    CArmsPoroto(void) {}
    virtual ~CArmsPoroto(void)
    {
        map<string, CArms*>::iterator ProtoIter = m_ArmsProtoMap.begin();
 
        while(ProtoIter != m_ArmsProtoMap.end())
        {
            SAFE_DELETE(ProtoIter->second);
            ++ProtoIter;
        }
        m_ArmsProtoMap.clear();
    }
};
 
// Composite.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
//
 
#include "stdafx.h"
#include "composite.h"
 
 
int _tmain(int argc, _TCHAR* argv[])
{
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    //_CrtSetBreakAlloc(219);
#endif
 
    CArmsPoroto ProtoCreator;
 
    ProtoCreator.InitArmsProto();
 
    CArms* pVulcan = ProtoCreator.GetCloneArms("CVulcan");
    CArms* pPistol = ProtoCreator.GetCloneArms("CPistol");
    CArms* pRocket = ProtoCreator.GetCloneArms("CRocket");
    CArms* pAllFire = ProtoCreator.GetCloneArms("CAllArmsFire");
 
    pVulcan->ArmsFire();
    pPistol->ArmsFire();
    pRocket->ArmsFire();
    pAllFire->ArmsFire();
        
    SAFE_DELETE(pVulcan);
    SAFE_DELETE(pPistol);
    SAFE_DELETE(pRocket);
    SAFE_DELETE(pAllFire);
 
    return 0;
}
 
 





Posted by JJOREG

브릿지패턴 --------------------------------------------------------------------------------------------------

객체란 선언과 구현으로 나뉜다.

선언이란 외부에 공개되는 인터페이스(함수나 맴버들)을 의미하며.

구현이란 인터페이스의 실제적인 동작을 정의해 놓고 있다.

하지만 하나의 구현파일안에 조건에 따른 다른 내용으로 분류되거나 하는 일이 있을수 있다.

하나의 클래스가 어떠한 일을 하는데 조건문에 따른 코드가 너무 길어져서 가독성이 떨어지고 처리해야할 코드가 길어진다면 어떻게 해야할까?

혹은 몇개의 함수만 다른 동작을 하고 나머지는 완전히 똑같은 동작을 하는 클래스가 여러개 있을때.

이들을 어떻게 하면 효율적으로 모으고 관리할 수 있을까?

그에 대한 새로운 방식을 지원해주는 것이 브릿지 패턴이라고 할 수 있다.


패턴적용 스토리 -----------------------------------------------------------------------------------------------

당신은 몬스터의 인공지능을 맡게 되었다. 

그런데 완전히 같은 몬스터라도 인공지능이 다르게 구현될 수 있다고 한다.

즉 같은 몬스터 A라도

소심한 몬스터A

대담한 몬스터A

비열한 몬스터A

같은 식으로 구현이 될 수 있다는 이야기 이다.

그럼 그것을 효율적으로 해결하기 위한 방법을 보자.


uml -----------------------------------------------------------------------------------------------


몬스터 클래스는 내부에 브릿지를 가지고 있다. 이 브릿지는 몬스터의 AI를 담당한다.

몬스터 AI를 담당하는 브릿지가 있기 때문에 몬스터 클래스 내부에서는 실제적인 AI의 동작을

몬스터끼리 달라져야할 부분만 구성하고 다른 부분은 몬스터 내부의 메소드에서 처리하면 된다.

즉 인터페이스의 구현을 연결된 브릿지에 맡김으로 해서 한 클래스에 코드과중이나 역할을 분산시킬 수 있다.



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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#pragma once
 
#include "stdafx.h"
#include "include.h"
 
enum MONSTER_AI
{
    MONSTER_AI_WILD,
    MONSTER_AI_CHICKEN,
    MONSTER_AI_BASTARD
};
 
typedef struct tagMonsterInfo
{
    MONSTER_AI    iAiPatton;
    int            iAtt;
 
    tagMonsterInfo(void) {}
    tagMonsterInfo(const MONSTER_AI& _iAiPatton, const int& _iAtt)
    {
        iAiPatton = _iAiPatton;
        iAtt = _iAtt;
    }
 
}MONSTERINFO, *PMONSTERINFO;
 
class CMonsterAiBridge
{
public:
    virtual void AiAction(const MONSTERINFO& _MonsterInfo) const = 0;
 
public:
    CMonsterAiBridge(void) {}
    virtual ~CMonsterAiBridge(void) {}
};
 
class CWildMonsterAi
    : public CMonsterAiBridge
{
public:
    virtual void AiAction(const MONSTERINFO& _MonsterInfo) const
    {
        cout << "************* 사나운 몬스터AI *************" << endl;
        cout << "사나우니까 공격!" << _MonsterInfo.iAtt << "피해를 입혔다" << endl;
        cout << "사나우니까 공격!" << _MonsterInfo.iAtt << "피해를 입혔다" << endl;
        cout << "사나우니까 공격!" << _MonsterInfo.iAtt << "피해를 입혔다" << endl;
        cout << endl;
    }
 
public:
    CWildMonsterAi(void) {}
    virtual ~CWildMonsterAi(void) {}
};
 
class CChickenMonsterAi
    : public CMonsterAiBridge
{
public:
    virtual void AiAction(const MONSTERINFO& _MonsterInfo) const
    {
        cout << "************* 겁쟁이 몬스터AI *************" << endl;
        cout << "플레이어와 거리가 가깝다! 도망!" << endl;
        cout << "플레이어와 거리가 가깝다! 도망!" << endl;
        cout << "거리가 벌어졌으니 활들고 공격!" << _MonsterInfo.iAtt << "피해를 입혔다" << endl;
        cout << endl;
    }
 
public:
    CChickenMonsterAi(void) {}
    virtual ~CChickenMonsterAi(void) {}
};
 
class CBastardMonsterAi
    : public CMonsterAiBridge
{
public:
    virtual void AiAction(const MONSTERINFO& _MonsterInfo) const
    {
        cout << "************* 비열한 몬스터AI *************" << endl;
        cout << "항복! 뿌잉뿌잉" << endl;
        cout << "플레이어가 전투태세를 풀었다!" << endl;
        cout << "방심하고 있으니 공격!" << _MonsterInfo.iAtt << "피해를 입혔다" << endl;
        cout << "플레이어가 공격하려고 한다!!" << endl;
        cout << "항복! 뿌잉뿌잉" << endl;
        cout << "플레이어가 전투태세를 풀었다!" << endl;
        cout << "방심하고 있으니 공격!" << _MonsterInfo.iAtt << "피해를 입혔다" << endl;
        cout << endl;
    }
 
public:
    CBastardMonsterAi(void) {}
    virtual ~CBastardMonsterAi(void) {}
};
 
class CMonster
{
private:
    MONSTERINFO          m_MonsterInfo;
    CMonsterAiBridge* m_MonsterAiBridge;
 
public:
    void InitMonster(void)
    { 
        switch(m_MonsterInfo.iAiPatton)
        {
        case MONSTER_AI_WILD:
            m_MonsterAiBridge = new CWildMonsterAi();
            break;
        case MONSTER_AI_CHICKEN:
            m_MonsterAiBridge = new CChickenMonsterAi();
            break;
        case MONSTER_AI_BASTARD:
            m_MonsterAiBridge = new CBastardMonsterAi();
            break;
        }
    }
 
    void AiAction(void)
    {
        m_MonsterAiBridge->AiAction(m_MonsterInfo);
    }
 
public:
    CMonster(void) {}
    CMonster(const MONSTERINFO& _MonsterInfo) 
    {
        m_MonsterInfo = _MonsterInfo;
    }
    ~CMonster(void
    {
        SAFE_DELETE(m_MonsterAiBridge);
    }
};
 
// Bridge.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
//
 
#include "stdafx.h"
#include "Bridge.h"
 
int _tmain(int argc, _TCHAR* argv[])
{
#ifdef _DEBUG
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
 
    CMonster* MonsterWild = new CMonster(MONSTERINFO(MONSTER_AI_WILD, 15));
    CMonster* MonsterChicken = new CMonster(MONSTERINFO(MONSTER_AI_CHICKEN, 15));
    CMonster* MonsterBastard = new CMonster(MONSTERINFO(MONSTER_AI_BASTARD, 15));
 
    MonsterWild->InitMonster();
    MonsterChicken->InitMonster();
    MonsterBastard->InitMonster();
 
    MonsterWild->AiAction();
    MonsterChicken->AiAction();
    MonsterBastard->AiAction();
 
    SAFE_DELETE(MonsterWild);
    SAFE_DELETE(MonsterChicken);
    SAFE_DELETE(MonsterBastard);
 
    return 0;
}






Posted by JJOREG

uml의 관계 표시화살표 --------------------------------------------------------------------------------------------------

앞서 UML의 표시 관계도를 단순히 화살표로 하다 이번에 아답터패턴에서 각 생성이나 포함하고 있는 객체들에 대한 관계에 대해서 너무 명확하지 못하게 작성하고 있었던 것 같다.
이제부터는 좀더신경을 써보려고 인터넷을 뒤져서 짱오리님의 블로그에서 UML의 기본에 대해서 알아봤다.

클래스----------------------------------------------------------------------------------------------------------------------------

맨위부터 

1. 클래스명

2. 맴버변수

3. 맴버함수를 의미한다.


앞에 붙은 - +들의 의미는

+ public

- private

# protected


코드로 봐보자.


객체----------------------------------------------------------------------------------------------------------------------------


관계표현(Relationships)-------------------------------------------------------------------------------------------------------------------------


서로 의미있는 클래스들의 관계에는 크게 4가지 종류가 있다.


일반적인 의미의 연결 관계인 연관( association ) 관계.

전체와 부분을 나타내는  집합( aggregation )  관계.

다른 클래스의 재산을 물려받는 상속( inheritance ) 관계.

한 클래스가 다른 클래스에 영향을 미치는 의존( dependency ) 관계.


관계를 표현해 보면 다음과 같다.


의존( dependency )--------------------------------------------------------------------------------------------------------

association 과 dependency 를 구분짓는 가장 큰 기준은 ' 참조하는 클래스 인스턴스의 레퍼런스를 계속 유지하고 있느냐, 아니냐 '


표시방법


설명

A클래스는 C 클래스를 내부에 맴버를 가지고 있거나 참조하고 있다.

하지만 함수 내부의 지역적으로 사용하고 있으며 A클래스가 사라진다고 해서 C클래스가 사라지지는 않는다.


주로 다음과 같은 세 가지 경우에 의존 관계로 표현한다.


1. 한 클래스의 메소드가 다른 클래스의 객체를 인자로 받아 그 메소드를 사용한다.

  ( 가장 일반적 ) 

2. 한 클래스의 메소드가 또 다른 클래스의 객체를 반환한다.

3. 다른 클래스의 메소드가 또 다른 클래스의 객체를 반환한다. 이때 이 메소드를 호출하여

   반환되는 객체의 메소드를 사용한다.


연관( association )--------------------------------------------------------------------------------------------------------


표시방법

   


설명

한 객체가 다른 객체와 연결되어 있음을 나타낼 때 그들을 연관관계로 지칭한다. 이러한 

연관관계에서 중요하게 볼 점은 ' 연관 관계의 방향( navigability ) 과 멀티플리시티

( multiplicity ) 이다.



양방향 연관 관계 : 연결된 클래스들이 서로의 존재를 알고 있다는 의미이다.

위의 UML 을 해석하자면 House 와 Person 클래스는 서로의 존재를 알고 있으며, 반드시 

한 사람 이상이 House에 속해야 한다는 것을 뜻한다. 



단방향 연관 관계 : House 클래스는 Person 클래스의 존재를 알고 있지만, Person 은 

House 클래스의 존재를 모르고 있다고 이해하면 된다. 이와 같은 경우는 House 클래스만 

Person 클래스에 대한 참조값을 가지고 있고, Person 은 House 에 대한 어떠한 참조값도 

가지고 있지 않는다.  



관계 표현을 나타낸 그림에서 보면 일반 연관과 특수 연관이라고 나뉘어 지는데, 

특수 연관이라는 것은 임의로 만든 단어이다.  일반 연관이란 앞에서 살펴본 association 을 

나타내며,  association 중에서도 ' 부분과 전체 ' 로 나눌 수 있는 관계를 aggregation 과 

composition 으로 묶어서 분류한 것이다.


aggregation 과 composition 은 모두 association 의 한 특별한 형태로 각각을 구분하는 

기준은  ' life cycle 이 같느냐, 같지 않느냐 ' 이다. life cycle 이란 클래스 인스턴스의 

생명 주기를 말하는 것으로 생성에서 소멸까지의 과정을 말한다. 즉, life cycle 이 같다는 것은

관계된 클래스 혹은 그 인스턴스의 생성과 소멸이 동시에 이루어진다는 것을 뜻한다.


쉽게 예를 들어 표현하자면 모자와 안경을 쓴 사람을 놓고 보자. 현재 이 사람을 구성하고 있는 

요소에는 눈, 팔, 다리와 같이 사람이 죽으면 같이 없어지는 요소들이 있고, 안경 모자와 같이 

바꿔 사용할 수 있는 요소들이 있다. 즉, 눈, 팔, 다리는 사람과 life cycle 이 같은

composition 관계 이고, 안경이나 모자는 aggregation 관계인 것이다.


즉 A클래스는 B클래스를 가지고 내부적으로 B클래스의 레퍼런스를 유지하지만 딱히 라이프사이클이 같거나 내부적으로 생성하고 있지는 않다.


상속( inheritance )--------------------------------------------------------------------------------------------------------


표기


설명

B클래스는 A클래스를 상속한다.


집합( aggregation )--------------------------------------------------------------------------------------------------------

설명

내부적으로 A클레스는 B클래스를 내부적으로 참조 하고 있지만

전체객체의 생성시기가 같을 필요도 없고 한쪽이 소멸된다고해서 나머지가 소멸되는 것은 아니다.

또한 컴퓨터의 모니터나 키보드는 언제든 다른 컴퓨터에 떼어주거나 혹은 파기될 수 있다.


구성( composition )--------------------------------------------------------------------------------------------------------


설명

A클래스는 B클래스를 가지고 있고 두 클래스의 라이프 사이클은 완전히 같다. A클래스가 사라지면 B클래스도 사라진다.


인터페이스( Interface )--------------------------------------------------------------------------------------------------------


설명
인터페이스는 자바와 C#에서 사용하는 개념으로 추후 설명한다.


Posted by JJOREG

아답터패턴 --------------------------------------------------------------------------------------------------

선생님은 말하셨다. 악마같은 패턴이하나 있는데 그중 하나가 아답터 패턴이라고.

아답터 패턴은 전혀 연관이 없는 녀석을 하나의 클래스로 만들어 새로운 클래스를 창조하거나.

두개의 연관없는 기능을 하나로 묶을 수 있다는 것이다.

즉 남의 코드를 마구 가져다 쓸때 매우 도움이 될 수도 있는 패턴이다.


아답터 클래스를 만드는 방식은 2가지가 있다.

일단 클래스 Target와 클래스 Adaptee라는 전혀 다른 기능을 가진 클래스가 있다고 치자.

(물론 하나의 애플리케이션 안에 있을 것 이므로 기본적인 목표는 동일할 수 있다.)

그런데 엮일줄 몰랐던 이 클래스들의 기능이 혼합된 새로운 기능을 만들라고 한다.

새로운 클래스를 만드는 것은 의외로 간단하다. 그냥 하나의 클래스를 만들고 두 클래스의 코드를 복사해서 붙여넣고 조정좀 해주면 되니까.

하지만 이런짓은 코드의 중복을 가져온다. 코드를 중복하지 않고 기능을 추가하거나 새로운 클래스를 만들어 낼 수는 없을까?

그걸 위한 아답터패턴이고 2가지 정도의 방법이 있다.


방법1. Adapter클래스 두개의 클래스를 상속받는다. 다중 상속이다. 하지만 상속을 통해서 adapter클래스는 두개의 클래스의 기능을 모두 사용할 수 있게 되었다. 

그러면서 다형성을 사용하여 어느 패턴의 형식으로도 관리될 수 있다.


방법2. Adapter클래스가 하나의 클래스를 상속받고 다른 클래스는 포함하게 된다. 내부에 포함된 adaptee의 함수를 사용할수 있지만 

오버라이드를 통해서 상위 클래스의 함수에 새로운 기능을 추가하는 일은 힘들다.


패턴적용 스토리 -----------------------------------------------------------------------------------------------

당신은 스킬을 만들라는 요청을 받았다.

그런데 여기서 웃기는 문제가 생겼다. 기존에는 공격스킬과 자신을 회복하는스킬을 나누어 놓자고 하고는 이제는 두개가 섞여있는 체력흡수라는 스킬을 만들어 내라고 한다.

즉 CATTSkill CSelfHEALSkill클래스의 스킬이 혼합된 스킬을 만들라고 하고 있다.

CMIXSkill클래스를 새롭게 만들기로 결정했다. 하지만.

코드의 중복은 피하면서 양쪽 모두의 효과를 동시에 사용할 수 있는 방법으로 아답터 패턴을 사용해보자.


uml -----------------------------------------------------------------------------------------------



양쪽을 모두 상속받는 CMixSkillOne과 한쪽은 상속받고 한쪽을 포함하는 CMixSkillTwo는 같은 동작을 하지만 포함과 상속이라는 약간의 차이가 있습니다.

하지만 양쪽의 인터페이스를 상속받으면서도 다른 모습을 보여줍니다.

한쪽은 인터페이스를 가상함수로 오버로딩 하고 있고.

한쪽은 새롭게 재정의 해서 사용하고 있습니다.

즉 응용하기에 따라 다양한 방법으로 혼합 합성이 가능함을 보여줍니다.



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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#pragma once
 
#include "stdafx.h"
#include "include.h"
 
typedef struct tagSkill
{
    int    iTarget;
    int    iOption;
 
    void Setting(const tagSkill& _Skill)
    {  
        *this = _Skill; 
    }
 
    void Setting(const int& _Target, const int& _Option)
    { 
        iTarget = _Target;
        iOption = _Option;
    }
 
    void tagMonster(void)
    { 
        iTarget = 0;
        iOption = 0; 
    };
 
}SKILLINFO, *PSKILLINFO;
 
class CAttSkill
{
protected:
    SKILLINFO m_SkillInfo;
 
public:
    virtual void Setting(int _Target, int _Option)
    { m_SkillInfo.Setting(_Target, _Option); }
    virtual void Setting(tagSkill& _Skill)
    { m_SkillInfo.Setting(_Skill); }
 
public:
    virtual void Effect(void)
    {
        cout << m_SkillInfo.iTarget << "번 몬스터에게 공격" << endl;
        cout << m_SkillInfo.iOption << "데미지를 입혔다." << endl;
    }
 
public:
    CAttSkill(void) {}
    ~CAttSkill(void) {}
};
 
class CSelfHealSkill
{
protected:
    int iOption;
 
public:
    virtual void Setting(const int& _Option)
    { iOption = _Option; }
 
public:
    void Effect(void)
    {
        cout << "자신에게 회복효과 적용" << endl;
        cout << iOption << "의 체력을 회복했다." << endl;
    }
 
public:
    CSelfHealSkill(void) {}
    ~CSelfHealSkill(void) {}
};
 
class CMixSkillOne
    : public CAttSkill, public CSelfHealSkill
{
public:
    virtual void Setting(const int& _iTarget, const int& _Option1, const int& _Option2)
    {
        m_SkillInfo.iTarget = _iTarget;
        m_SkillInfo.iOption = _Option1;
        iOption = _Option2;
        //Setting(iTarget, _Option1);
        //SelfSetting(_Option2);
    }
 
public:
    void Effect(void)
    {
        CAttSkill::Effect();
        CSelfHealSkill::Effect();
    }
 
 
public:
    CMixSkillOne(void) {}
    ~CMixSkillOne(void) {}
};
 
class CMixSkillTwo
    : public CAttSkill
{
private:
    CSelfHealSkill m_SelfHeal;
 
public:
    virtual void MixSetting(const int& _iTarget, const int& _Option1, const int& _Option2)
    {
        m_SkillInfo.iTarget = _iTarget;
        m_SkillInfo.iOption = _Option1;
        m_SelfHeal.Setting(_Option2);
    }
 
public:
    void MixEffect(void)
    {
        Effect();
        m_SelfHeal.Effect();
    }
 
public:
    CMixSkillTwo(void) {}
    ~CMixSkillTwo(void) {}
};
 
// Adapter.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
//
 
#include "stdafx.h"
#include "Adapter.h"
 
 
int _tmain(int argc, _TCHAR* argv[])
{
    int Target = 0;
    int Option = 10;
 
    cout << "************ AttSkill ************" << endl;
 
    CAttSkill AttSkill;
    AttSkill.Setting(Target, Option);
    AttSkill.Effect();
 
    cout << "************ SelfHealSkill ************" << endl;
 
    CSelfHealSkill SelfHeal;
    SelfHeal.Setting(Option);
    SelfHeal.Effect();
 
    cout << "************ MixSkillOne ************" << endl;
 
    CMixSkillOne MixSkillOne;
 
    MixSkillOne.Setting(Target, Option, Option);
    MixSkillOne.Effect();
 
    cout << "************ MixSkillTwo ************" << endl;
 
    CMixSkillTwo MixSkillTwo;
 
    MixSkillTwo.MixSetting(Target, Option, Option);
    MixSkillTwo.MixEffect();
 
    return 0;
}


결과 -----------------------------------------------------------------------------------------------




'게임개발공부 > 디자인패턴' 카테고리의 다른 글

구조패턴 <브릿지 패턴> (가교)  (0) 2013.12.23
uml 관계도 좀더 명확히  (1) 2013.12.22
메인프레임 작업 01  (0) 2013.12.21
생성패턴 <싱글톤 패턴>  (0) 2013.12.18
생성패턴 <프로토 타입>  (0) 2013.12.17
Posted by JJOREG
이전버튼 1 2 이전버튼