Command Pattern
커맨드 패턴은 요청 자체를 캡슐화하는 패턴이다. 이를 통해 요청이 서로 다른 사용자를 매개변수로 만들고 요청을 대기시키거나 로깅하며 되돌릴 수 있는 연산을 지원한다.
활용성
수행할 동작의 매개변수화
수행할 동작을 매개변수화 할 수 있다. 절차지향 프로그래밍에서는 이를 콜백 함수 즉, 어딘가 등록되었다가 나중에 호출되는 함수를 사용해서 이런 매개변수화를 표현할 수 있다.
서로 다른 시간에 요청을 명시, 저장, 실행
커맨드 객체는 원래 요청과 다른 생명주기가 있다. 요청을 받아 처리하는 객체가 주소 지정 방식과는 독립적으로 표현될 수 있다면 커맨드 객체를 다른 프로세스에게 넘겨주고 거기서 해당 처리를 수행할 수 있다.
실행 취소 기능을 지원
커맨드의 Execute() 연산은 상태를 저장할 수 있는데 이를 통해 지금까지 얻은 결과를 바꿀 수 있다. Unexecute() 연산을 추가하면 된다.
재적용 가능하도록 지원
커맨드 인터페이스를 확장해서 load()와 store()연산을 정의하면 상태의 변화를 지속적으로 저장소에 저장해둘 수 있다. 이를 통해 시스템이 고장났을 때 재적용이 가능하도록 변경 과정에 대한 로깅을 지원하게 할 수 있다.
기본적인 연산 조합으로 만든 상위 수준 연산을 만듬
기본적인 연산의 조합으로 만든 상위 수준 연산을 써서 시스템을 구조화할 수 있다. 이런 시스템의 일반적 특성은 트랜잭션을 지원한다는 점이다.
커맨드 패턴 사용에 따른 결과
- 연산을 호출하는 객체와 연산 수행 방법을 구현하는 객체를 분리.
- 명령을 여러개 복합해 복합 명령을 만들 수 있다.
- 새로운 커맨드 객체를 추가하기 쉽다.
커맨드
구조
커맨드의 구조는 다음과 같다.
C++ 구현
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| void CommandPattern::buildMacro() { Receiver* receiver = new Receiver; CommandComposite* keyboardInput1 = new InputCommandComposite(new KeyboardInputCommand("This is new Macro")); CommandComposite* keyboardInput2 = new InputCommandComposite(new KeyboardInputCommand("Macro Start")); CommandComposite* rightClick = new ClickCommandComposite(new RightClickCommand()); CommandComposite* keyboardInput3 = new InputCommandComposite(new KeyboardInputCommand("Macro End"));
receiver->addMacro(keyboardInput1); receiver->addMacro(keyboardInput2); receiver->addMacro(rightClick); receiver->addMacro(keyboardInput3);
receiver->action();
receiver->removeMacro(); receiver->removeMacro();
receiver->action(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Receiver { std::vector<CommandComposite*> command; public: void addMacro(CommandComposite* composite) { command.emplace_back(composite); }
void removeMacro() { command.pop_back(); }
void action() { for(CommandComposite* composite : command) composite->execute(); } };
|
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
| class CommandComposite { public: virtual ~CommandComposite() {} virtual void execute() = 0; };
class InputCommandComposite : public CommandComposite { InputCommand* command; public: InputCommandComposite(InputCommand* clickCommand) : command(clickCommand) {}
void execute() override { command->execute(); } };
class ClickCommandComposite : public CommandComposite { ClickCommand* command; public: ClickCommandComposite(ClickCommand* clickCommand) : command(clickCommand) {}
void execute() override { command->execute(); } };
|
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
| class Command { public: virtual ~Command() {} virtual void execute() = 0; };
class ClickCommand : public Command { public: virtual ~ClickCommand() {}; };
class RightClickCommand : public ClickCommand { public: void execute() override { std::cout<<"execute right click command"<<std::endl; } };
class InputCommand : public Command { public: virtual ~InputCommand() {}; };
class KeyboardInputCommand : public InputCommand { std::string cmd; public: KeyboardInputCommand(std::string cmd) : cmd(cmd) {}
void execute() override { std::cout<<"execute keyboard command "<<cmd<<std::endl; } };
|
java 구현
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
| public class Client { public static void main(String[] args) { Receiver receiver = new Receiver(); CommandComposite inputCommandComposite1 = new InputCommandComposite(new KeyboardInputCommand("This is new Macro")); CommandComposite inputCommandComposite2 = new InputCommandComposite(new KeyboardInputCommand("Macro Start")); CommandComposite clickCommandComposite = new ClickCommandComposite(new RightClickCommand()); CommandComposite inputCommandComposite3 = new InputCommandComposite(new KeyboardInputCommand("Macro End"));
receiver.add(inputCommandComposite1); receiver.add(inputCommandComposite2); receiver.add(clickCommandComposite); receiver.add(inputCommandComposite3);
receiver.action();
receiver.remove(); receiver.remove();
receiver.action(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class Receiver { private List<CommandComposite> commandComposites;
public Receiver() { commandComposites = new ArrayList<>(); }
public void add(CommandComposite commandComposite) { commandComposites.add(commandComposite); }
public void remove() { commandComposites.remove(commandComposites.size() - 1); }
public void action() { for(CommandComposite commandComposite : commandComposites) commandComposite.execute(); } }
|
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
| public interface CommandComposite { void execute(); }
public class InputCommandComposite implements CommandComposite{ private InputCommand command;
public InputCommandComposite(InputCommand command) { this.command = command; }
@Override public void execute() { command.execute(); } }
public class ClickCommandComposite implements CommandComposite{ private ClickCommand command;
public ClickCommandComposite(ClickCommand command) { this.command = command; }
@Override public void execute() { command.execute(); } }
|
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
| public interface Command { void execute(); }
public interface InputCommand extends Command{ }
public class KeyboardInputCommand implements InputCommand{ private String cmd;
KeyboardInputCommand(String cmd) { this.cmd = cmd; }
@Override public void execute() { System.out.println("execute keyboard command" + cmd); } }
public interface ClickCommand extends Command{ }
public class RightClickCommand implements ClickCommand{ @Override public void execute() { System.out.println("execute right click command"); } }
|