본문 바로가기
스터디/헤드퍼스트 디자인패턴

[헤드퍼스트 디자인패턴] 06. 커맨드 패턴(Command Pattern)

by 디토20 2022. 7. 10.
반응형

 

 

 

[헤드퍼스트 디자인패턴] 06. 커맨드 패턴(Command Pattern)

 

1. 커맨드 패턴이란?

- 커맨드 패턴을 사용하면 요청 내역을 객체로 캡슐화해서 객체를 서로 다른 요청 내역에 따라 매개변수화할 수 있다. 이러면 요청을 큐에 저장하거나 로그로 기록하거나 작업 취소 기능을 사용할 수 있다.

 

커맨드 패턴은 크게 Invoker(호출자), Receiver(수신자), Command(명령) 객체로 구분된다. 인보커는 기능의 실행을 요청하고 리시버는 명령을 수행하는 객체다.

 

 

 

실행될 기능을 캡슐화함으로써 기능의 실행을 요구하는 호출자(Invoker) 클래스와 실제 기능을 실행하는 수신자(Receiver) 클래스 사이의 의존성을 제거한다. 따라서 실행될 기능의 변경에도 호출자 클래스를 수정 없이 그대로 사용 할 수 있다.

 

식당을 예로들어보자.

 

1. 손님이 웨이터에게 주문을 한다.

2. 웨이터가 고객의 주문을 주문서에 적는다.

3. 웨이터는 주문서를 주방에 전달하여 주문을 요청한다.

4. 요리사는 주문서에 적힌 주문대로 음식을 자신의 노하우로 만든다.

 

손님       ==    클라이언트

웨이터    ==    인보커 객체

주문서    ==    커맨드 객체

주방장    ==    리시버 객체

주문을 하는것 == setCommand()

주문을 요청하는것 == execute()

 

 

2. 요구사항

조명, 팬, 욕조, 오디등의 장비를 제어할 수 있는 리모컨을 만들어달라!

 

 

3. 첫번째 커맨드 객체 구현

3.1 커맨드 인터페이스 구현

public interface Command {
   public void execute();
}

커맨드 객체는 모두 같은 인터페이스를 구현해야 한다.

 

 

3.2 조명을 켤 때 필요한 커맨드 클래스 구현

public class LightOnCommand implements Command {
   Light light;
   
   public LightOnCommand(Light light) {
      this.light = ligth;
   }
   
   public void excute() {
      light.on();
   }

}

 

3.3 간단한 리모컨 클래스 구현

버튼이 하나밖에 없는 리모컨이라고 가정하고 커맨드를 실행해 줄 인보커 클래스를 만들어 보자.

public class SimpleRemoteControl {
  Command slot;
  public SimpleRemoteControl() {}
  
  public void setCommand(Command command) {
     slot = command;
  }
  
  public void buttonWasPressed() {
     slot.execute();
  }
}

 

 

3.4 간단한 테스트 클래스

public class RemoteControlTest {
  public static void main(String[] args) {
    SimpleRemoteControl remote = new SimpleRemoteControl();
    Light light = new Light();
    LightOnCommand ligthOn = new LightOnCommand(light);
    
    remote.setCommand(lightOn);
    remote.buttonWasPressed();
  }
}

 remote는 invoker, Light는 receiver가 된다. remote에 LightOnCommand를 넣고, button을 눌러 Light를 킬 수 있다.

 

 

 

4. 기능이 여러개 있는 만능 리모컨 구현

public class RemoteControl {

	Command[] onCommands;
	Command[] offCommands;
	Command undoCommand;

	public RemoteControl() {
		onCommands = new Command[7];
		offCommands = new Command[7];

		Command noCommand = new NoCommand(); // 아무 동작도 없는 커맨드 객체 일종의 Null 객체

		for (int i = 0; i < 7; i++) {
			onCommands[i] = noCommand;
			offCommands[i] = noCommand;
		}
		undoCommand = noCommand;

	}

	public void setCommand(int slot, Command onCommand, Command offCommand) {
		onCommands[slot] = onCommand;
		offCommands[slot] = offCommand;

	}

	public void onButtonWasPushed(int slot) {
		onCommands[slot].execute();
		undoCommand = onCommands[slot];

	}

	public void offButtonWasPushed(int slot) {
		offCommands[slot].execute();
		undoCommand = offCommands[slot];

	}

	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer();

		for (int i = 0; i < 7; i++) {
			sb.append(onCommands[i].getClass().getName() + " / " + offCommands[i].getClass().getName() + "\n");
		}
		return sb.toString();

	}

}

 

 

 

5. 하나의 버튼으로 여러 기능을 하는 매크로 리모컨

public class MacroCommand implements Command {

	Command[] commands;

	public MacroCommand(Command[] commands) {
		this.commands = commands;

	}

	public void execute() {
		for (int o = 0; i < commands.length; i++) {
			commands[i].execute();

		}

	}

	public void undo() {
		for (int o = 0; i < commands.length; i++) {
			commands[i].undo();

		}

	}

}

=======================================================================

Command[] macroOn = {lightOn, stereoOn, tvOn };
Command[] macroOff = {lightOff, stereoOff, tvOff };

Macrocommand commandMacroOn = new MacroCommand(macroOn);
Macrocommand commandMacroOff = new MacroCommand(macroOff);

remoteControl.setCommand(0, commandMacroOn, commandMacroOff);

 

 

728x90
반응형

댓글