커맨드 패턴(Command Pattern)

디자인패턴 2014. 11. 11. 14:24

1. 커맨드 패턴이란?


 커맨드 패턴에서는 요구 사항을 객체로 캡슐화 할 수 있으며, 매개변수를 써서 여러 가지 다른 요구 사항을 집어 넣을 수 있다. 그리고 작업을 요청하는 쪽과 작업을 처리하는 쪽을 분리할 수 있다. 또한 요청 내역을 에 저장하거나 로그로 기록할 수 있으며, 작업취소 기능도 지원 가능하다.

(1) Client
 클라이언트는 ConcreteCommand를 생성하고 Receiver를 설정한다.

(2) Receiver
 Receiver는 요구 사항을 수행하기 위해 어떤 일을 처리해야 하는지 알고 있는 객체

(3) Invoker
 Invoker에는 명령(Command)이 들어있으며, execute() 메소드를 호출함으로써 커맨드 객체에게 특정 작업을 수행해 달라는 요구를 한다.

(4) Command
 Command는 모든 커맨드 객체에서 구현해야 하는 인터페이스(Interface)이다. Receiver에게 시킬 모든 명령은 execute() 메소드 호출을 통해 수행되며, 이 메소드에서는 Receiver에 특정 작업을 처리하라는 지시를 전달한다.

(5) ConcreteCommand
 ConcreteCommand는 특정 행동과 Receiver 사이를 연결(bind)한다. Invoker에서 excute() 호출을 통해 요청을 하면 ConcreteCommand 객체에서 Receiever에 있는 메소드를 호출함으로써 그 작업을 처리한다.

 행동과 Receiver를 Command 객체에 집어넣고, execute()라는 메소드 하나만 외부에 공개하여 요구 사항이 들어있는 Receiver 객체를 캡슐화한다.



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
// 모든 커맨드 객체에서 구현해야 하는 인터페이스(Interface)
// 모든 명령은 execute() 메소드 호출을 통해 수행되며, 이 메소드에서는 Receiver에 특정 작업을 처리하라는 지시를 전달한다.
public interface Command {
 public void execute();
 public void undo();
}
 
// ConcreteCommand
// 이 클래스는 천장팬 속도를 높이는 행동과 Receiver인 CeilingFan 사이를 bind한다.
public class CeilingFanHighCommand implements Command {
 CeilingFan ceilingFan;
 int prevSpeed;
  
 public CeilingFanHighCommand(CeilingFan ceilingFan) {
  this.ceilingFan = ceilingFan;
 }
  
 // Invoker에서 이 메소드를 호출하면 천장팬 속도를 높인다.
 // 이 때, undo 기능을 구현하기 위해 이전에 있던 속도 값을 저장해둔다.
 @Override
 public void execute() {
  prevSpeed = ceilingFan.getSpeed();
  ceilingFan.high();
 }
 
 // 이전 속도를 바탕으로 속도를 재조정한다.
 @Override
 public void undo() {
  if (prevSpeed == CeilingFan.HIGH) {
   ceilingFan.high();
  } else if (prevSpeed == CeilingFan.MEDIUM) {
   ceilingFan.medium();
  } else if (prevSpeed == CeilingFan.LOW) {
   ceilingFan.low();
  } else if (prevSpeed == ceilingFan.OFF) {
   ceilingFan.off();
  }
 }
 
}
 
public class CeilingFanOffCommand implements Command {
 CeilingFan ceilingFan;
 int prevSpeed;
  
 public CeilingFanOffCommand(CeilingFan ceilingFan) {
  this.ceilingFan = ceilingFan;
 }
  
 @Override
 public void execute() {
  prevSpeed = ceilingFan.getSpeed();
  ceilingFan.off();
 }
 
 @Override
 public void undo() {
  if (prevSpeed == CeilingFan.HIGH) {
   ceilingFan.high();
  } else if (prevSpeed == CeilingFan.MEDIUM) {
   ceilingFan.medium();
  } else if (prevSpeed == CeilingFan.LOW) {
   ceilingFan.low();
  } else if (prevSpeed == CeilingFan.OFF) {
   ceilingFan.off();
  }
 }
 
}
 
// NoCommand 객체는 일종의 Null Object(널 객체)이다.
// 리턴할 객체는 없지만 클라이언트 쪽에서 null을 처리하지 않아도 되게 하고 싶을 때 활용하면 좋다.
public class NoCommand implements Command {
 
 @Override
 public void execute() {
   
 }
 
 @Override
 public void undo() {
   
 }
 
}
 
// Receiver
// 천장팬을 작동시키는 클래스
public class CeilingFan {
 public static final int HIGH = 3;
 public static final int MEDIUM = 2;
 public static final int LOW = 1;
 public static final int OFF = 0;
 String location;
 int speed;
  
 public CeilingFan(String location) {
  this.location = location;
  speed = OFF;
 }
  
 public void high() {
  speed = HIGH;
 }
  
 public void medium() {
  speed = MEDIUM;
 }
  
 public void low() {
  speed = LOW;
 }
  
 public void off() {
  speed = OFF;
 }
  
 public int getSpeed() {
  return speed;
 }
}
 
// Invoker
public class RemoteControl {
 Command[] onCommands;
 Command[] offCommands;
 Command undoCommand;
  
 public RemoteControl() {
  onCommands = new Command[7];
  offCommands = new Command[7];
   
  Command noCommand = new NoCommand();
  for (int i = 0; i < 7; i++) {
   onCommands[i] = noCommand;
   offCommands[i] = noCommand;
  }
  undoCommand = noCommand;
 }
  
 // setCommand() 메소드로 리모컨의 각 슬롯에 특정 명령을 지정해놓는다.
 public void setCommand(int slot, Command onCommand, Command offCommand) {
  onCommands[slot] = onCommand;
  offCommands[slot] = offCommand;
 }
  
 // 특정 슬롯의 ON 버튼이 눌러지면, 해당 슬롯의 ONCommand의 execute() 메소드를 호출한다.
 public void onButtonWasPushed(int slot) {
  onCommands[slot].execute();
  undoCommand = onCommands[slot];
 }
  
 public void offbuttonWasPushed(int slot) {
  offCommands[slot].execute();
  undoCommand = offCommands[slot];
 }
  
 public String toString() {
  StringBuffer stringBuff = new StringBuffer();
  stringBuff.append("\n-------Remote Control--------\n");
  for (int i = 0; i < onCommands.length; i++) {
   stringBuff.append("[slot " + i + "] " + onCommands[i].getClass().getName() + "   "+offCommands[i].getClass().getName() + "\n");
  }
  return stringBuff.toString();
 }
  
 public void undoButtonWasPushed() {
  undoCommand.undo();
 }
}
 
// Client
public class RemoteLoader {
 
 /**
  * @param args
  */
 public static void main(String[] args) {
  RemoteControl remoteControl = new RemoteControl();
   
  CeilingFan ceilingFan = new CeilingFan("Living Room");
 
  CeilingFanHighCommand ceilingFanHigh = new CeilingFanHighCommand(ceilingFan);
  CeilingFanOffCommand ceilingFanOff = new CeilingFanOffCommand(ceilingFan);
   
  remoteControl.setCommand(2, ceilingFanHigh, ceilingFanOff);
   
  System.out.println(remoteControl);
  remoteControl.onButtonWasPushed(0);
  remoteControl.offbuttonWasPushed(0);
  remoteControl.undoButtonWasPushed();
   
  remoteControl.onButtonWasPushed(2);
  remoteControl.offbuttonWasPushed(2);
  remoteControl.undoButtonWasPushed();
 }
 
}









참고
Head FIrst Design Pattern : 스토리가 있는 패턴 학습법
http://www.gurubee.net/pages/viewpage.action?pageId=1507401


출처 - http://digitanomad.blogspot.kr/2013/02/command-pattern.html




출처 - http://digitanomad.blogspot.kr/2013/02/command-pattern.html

'디자인패턴' 카테고리의 다른 글

스트래티지 패턴(Strategy Pattern)  (0) 2014.11.11
퍼사드 패턴(Facade Pattern)  (0) 2014.11.11
싱글턴 패턴(Singleton Pattern)  (0) 2014.11.11
팩토리 패턴(Factory Pattern)  (0) 2014.11.11
옵저버 패턴(Observer Pattern)  (0) 2014.11.11
: