커맨드 패턴(Command Pattern)
디자인패턴 2014. 11. 11. 14:241. 커맨드 패턴이란?
커맨드 패턴에서는 요구 사항을 객체로 캡슐화 할 수 있으며, 매개변수를 써서 여러 가지 다른 요구 사항을 집어 넣을 수 있다. 그리고 작업을 요청하는 쪽과 작업을 처리하는 쪽을 분리할 수 있다. 또한 요청 내역을 큐에 저장하거나 로그로 기록할 수 있으며, 작업취소 기능도 지원 가능하다.
(1) Client
클라이언트는 ConcreteCommand를 생성하고 Receiver를 설정한다.
(2) Receiver
Receiver는 요구 사항을 수행하기 위해 어떤 일을 처리해야 하는지 알고 있는 객체
(3) Invoker
Invoker에는 명령(Command)이 들어있으며, execute() 메소드를 호출함으로써 커맨드 객체에게 특정 작업을 수행해 달라는 요구를 한다.
(4) Command
Command는 모든 커맨드 객체에서 구현해야 하는 인터페이스(Interface)이다. Receiver에게 시킬 모든 명령은 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 |