[읽기전에]
UML 다이어그램 : UML클래스 다이어그램 기본상식 http://hongjinhyeon.tistory.com/25
포스팅되는 디자인 패턴의 예는 스타크래프트를 기본으로 하였습니다 : 디자인 패턴을 시작하며 http://hongjinhyeon.tistory.com/24
<기본 정의 >
1. Command Pattern 정의
-커맨드 패턴을 이용하면 요구 사항을 객체로 갭슐화 할 수 있으며, 매개변수를 써서 여러 가지 다른 요구 사항을 집어 넣을수 있다.
또한 요청 내역을 큐에 저장하거나 로그로 기록 할 수 있으며, 작업취소 기능도 지원이 가능하다.
(Encapsulate a request as an object, thereby letting you parameterize clients with different requests,
queue or log requests, and support undoable operations.)
2. UML Diagram
3. 사용용도 및 장점
-사용자의 요청을 객체화 시킴으로써 ( 객체 안에 작업에 필요한 모든 내용이 들어가있음 ), 그 객체만 있으면 해당 커맨드가 어떤
작업을 수행했는지 알 수가있다. 그럼으로 해서 다시 취소작업을 수행한다거나 로그기능을 구현이 가능하다.
-커맨트 패턴은 커맨드에 알맞은 파라미터만 전달해주면 알아서 결과가 처리가된다. (예) 계산기
요청만 하면 내부적으로 알고리즘에 의해서 자동으로 처리가 된다.
4. 소스
01.
using
System;
02.
03.
namespace
DoFactory.GangOfFour.Command.Structural
04.
{
05.
/// <summary>
06.
/// MainApp startup class for Structural
07.
/// Command Design Pattern.
08.
/// </summary>
09.
class
MainApp
10.
{
11.
/// <summary>
12.
/// Entry point into console application.
13.
/// </summary>
14.
static
void
Main()
15.
{
16.
// Create receiver, command, and invoker
17.
Receiver receiver =
new
Receiver();
18.
Command command =
new
ConcreteCommand(receiver);
19.
Invoker invoker =
new
Invoker();
20.
21.
// Set and execute command
22.
invoker.SetCommand(command);
23.
invoker.ExecuteCommand();
24.
25.
// Wait for user
26.
Console.ReadKey();
27.
}
28.
}
29.
30.
/// <summary>
31.
/// The 'Command' abstract class
32.
/// </summary>
33.
abstract
class
Command
34.
{
35.
protected
Receiver receiver;
36.
37.
// Constructor
38.
public
Command(Receiver receiver)
39.
{
40.
this
.receiver = receiver;
41.
}
42.
43.
public
abstract
void
Execute();
44.
}
45.
46.
/// <summary>
47.
/// The 'ConcreteCommand' class
48.
/// </summary>
49.
class
ConcreteCommand : Command
50.
{
51.
// Constructor
52.
public
ConcreteCommand(Receiver receiver) :
53.
base
(receiver)
54.
{
55.
}
56.
57.
public
override
void
Execute()
58.
{
59.
receiver.Action();
60.
}
61.
}
62.
63.
/// <summary>
64.
/// The 'Receiver' class
65.
/// </summary>
66.
class
Receiver
67.
{
68.
public
void
Action()
69.
{
70.
Console.WriteLine(
"Called Receiver.Action()"
);
71.
}
72.
}
73.
74.
/// <summary>
75.
/// The 'Invoker' class
76.
/// </summary>
77.
class
Invoker
78.
{
79.
private
Command _command;
80.
81.
public
void
SetCommand(Command command)
82.
{
83.
this
._command = command;
84.
}
85.
86.
public
void
ExecuteCommand()
87.
{
88.
_command.Execute();
89.
}
90.
}
91.
}
-main 부분이 Client에 해당합니다.
5. 실행결과
Called Receiver.Action()
< 실제 적용 >
1. UML Diagram
2. 사용용도 및 장점
-스타크래프트에서 커맨드 패턴을 찾기가 힘들었습니다. Redo, Undo가 되는게 없더군요. 그와중에 발견한 스타크래프트 맵을 만들어주는 에디터(빙고)
-맵 에디터에서 유닛들을 배치하거나 지형(언덕, 물, 미네랄등)을 배치하고 다시 Undo도 할수잇고 Redo도 가능합니다.
-하나 하나의 명령어들을 객체화함으로써 Undo나 Redo가 가능하게 됩니다.
3. 소스
001.
using
System;
002.
using
System.Collections.Generic;
003.
using
System.Linq;
004.
using
System.Text;
005.
006.
namespace
Command
007.
{
008.
class
Program
009.
{
010.
static
void
Main(
string
[] args)
011.
{
012.
MapEditor mapEditor =
new
MapEditor();
013.
014.
mapEditor.Create(
"마린1"
,
"100"
,
"200"
);
015.
mapEditor.Create(
"마린2"
,
"200"
,
"400"
);
016.
mapEditor.Create(
"마린3"
,
"300"
,
"600"
);
017.
mapEditor.Delete(
"마린2"
,
"300"
,
"600"
);
018.
019.
mapEditor.Undo(3);
020.
mapEditor.Redo(3);
021.
022.
Console.ReadKey();
023.
024.
}
025.
026.
/// <summary>
027.
/// Receiver 클래스
028.
/// </summary>
029.
class
UnitManger
030.
{
031.
032.
public
void
CreatUnit(
string
_unitName,
string
_pointX,
string
_pointY)
033.
{
034.
Console.WriteLine(
"[{0}] 유닛을 X좌표 {1} , Y좌표 {2} 위치에 생성합니다."
, _unitName, _pointX, _pointY);
035.
}
036.
037.
public
void
DeleteUnit(
string
_unitName,
string
_pointX,
string
_pointY)
038.
{
039.
Console.WriteLine(
"[{0}] 유닛을 X좌표 {1} , Y좌표 {2} 위치에서 삭제합니다."
, _unitName, _pointX, _pointY);
040.
}
041.
042.
}
043.
044.
/// <summary>
045.
/// 추상 Command 생성
046.
/// </summary>
047.
abstract
class
Command
048.
{
049.
public
string
unitName;
050.
public
string
pointX;
051.
public
string
pointY;
052.
053.
public
abstract
void
Execute();
054.
}
055.
056.
/// <summary>
057.
/// 유닛 생성 Concreate 객체 생성
058.
/// </summary>
059.
class
CreatCommand : Command
060.
{
061.
062.
private
UnitManger unitManger;
063.
064.
/// <summary>
065.
/// 생성자
066.
/// </summary>
067.
/// <param name="_unitManger"></param>
068.
public
CreatCommand(UnitManger _unitManger,
string
_unitName,
string
_pointX,
string
_pointY)
069.
{
070.
this
.unitManger = _unitManger;
071.
this
.unitName = _unitName;
072.
this
.pointX = _pointX;
073.
this
.pointY = _pointY;
074.
}
075.
076.
public
override
void
Execute()
077.
{
078.
unitManger.CreatUnit(
this
.unitName,
this
.pointX,
this
.pointY);
079.
}
080.
081.
}
082.
083.
/// <summary>
084.
/// 유닛 삭제 Concreate 객체 생성
085.
/// </summary>
086.
class
DeleteCommand : Command
087.
{
088.
private
UnitManger unitManger;
089.
090.
/// <summary>
091.
/// 생성자
092.
/// </summary>
093.
/// <param name="_unitManger"></param>
094.
public
DeleteCommand(UnitManger _unitManger,
string
_unitName,
string
_pointX,
string
_pointY)
095.
{
096.
this
.unitManger = _unitManger;
097.
this
.unitName = _unitName;
098.
this
.pointX = _pointX;
099.
this
.pointY = _pointY;
100.
}
101.
102.
public
override
void
Execute()
103.
{
104.
unitManger.DeleteUnit(
this
.unitName,
this
.pointX,
this
.pointY);
105.
}
106.
107.
}
108.
109.
110.
class
MapEditor
111.
{
112.
private
UnitManger _uintManger =
new
UnitManger();
113.
private
List<Command> _commands =
new
List<Command>();
114.
private
int
_current = 0;
115.
116.
public
void
Create(
string
_unitName,
string
_pointX,
string
_pointY)
117.
{
118.
Command command =
new
CreatCommand(_uintManger, _unitName, _pointX, _pointY);
119.
command.Execute();
120.
121.
_commands.Add(command);
122.
_current++;
123.
}
124.
125.
public
void
Delete(
string
_unitName,
string
_pointX,
string
_pointY)
126.
{
127.
Command command =
new
DeleteCommand(_uintManger, _unitName, _pointX, _pointY);
128.
command.Execute();
129.
130.
_commands.Add(command);
131.
_current++;
132.
}
133.
134.
135.
public
void
Redo(
int
levels)
136.
{
137.
Console.WriteLine(
"\n---- Redo {0} levels "
, levels);
138.
139.
for
(
int
i = 0; i < levels; i++)
140.
{
141.
if
(_current <= _commands.Count - 1)
142.
{
143.
Command command = _commands[_current++];
144.
command.Execute();
145.
}
146.
}
147.
}
148.
149.
public
void
Undo(
int
levels)
150.
{
151.
Console.WriteLine(
"\n---- Undo {0} levels "
, levels);
152.
// Perform undo operations
153.
for
(
int
i = 0; i < levels; i++)
154.
{
155.
if
(_current > 0)
156.
{
157.
Command command = _commands[--_current]
as
Command;
158.
159.
if
((command
as
CreatCommand) !=
null
)
160.
{
161.
//생성일때 삭제처리
162.
Command commandTemp =
new
DeleteCommand(_uintManger, command.unitName, command.pointX, command.pointY);
163.
commandTemp.Execute();
164.
}
165.
else
166.
{
167.
//삭제일때 생성처리
168.
Command commandTemp =
new
CreatCommand(_uintManger, command.unitName, command.pointX, command.pointY);
169.
commandTemp.Execute();
170.
}
171.
172.
}
173.
174.
}
175.
176.
}
177.
178.
}
179.
180.
}
181.
}
4. 실행결과
5. 피드백
-커맨드 패턴의 핵심은 사용자의 요구사항 자체를 객체로 캡슐화 하는것이다.
-처음 UML 다이어그램을 봤을때 이게 먼가할정도로 좀 꼬여서 서로를 생성하고 소유하는거 같습니다.
-커맨드를 주문서, 인보커를 종업원, 리시버를 주방정 정도로 생각하시면 됩니다.
[참조]
-http://www.dofactory.com
-Head First Design Patterns
'프로젝트 설계 > 디자인 패턴' 카테고리의 다른 글
11. Iterator Pattern ( 이터레이터 / 반복자 패턴 C# ) (3) | 2012.10.09 |
---|---|
10. State Pattern ( 스테이트 / 상태 패턴 C# ) (4) | 2012.09.11 |
8. Strategy Pattern ( 스트래티지 / 전략 패턴 C# ) (9) | 2012.09.06 |
7. Observer Pattern ( 옵져버 패턴 C# ) (3) | 2012.09.05 |
6. Facade Pattern (퍼사드 패턴 C# ) (2) | 2012.09.04 |