만능 리모컨을 만든다고 가정하자. 여러 개의 버튼을 통해서 여러 기기들을 다룰 수 있는 리모컨이다. 하지만, 다양한 기기들은 서로 다른 기능들을 가지고 있기 때문에, 기기들이 공통적으로 가지는 기능을 인터페이스 화 시키는 것은 불가능에 가깝다. 그렇다고, 리모컨의 버튼마다 특정한 기능을 지정해버리면, OCP를 위배할 것이다.
이와 같은 문제는 Command Pattern을 이용해서 커맨드 객체를 추가하고, 작업을 요청하는 것과 작업을 처리하는 것을 분리함으로써 해결할 수 있다.
요청을 객체로 캡슐화해서 객체를 서로 다른 요청에 따라 매개변수화할 수 있다. 또한, 요청을 큐에 저장하거나 로그로 기록하거나 작업 취소 또한 가능하다.
커맨드 객체는 일련의 행동을 특정한 리시버와 연결해서 행동을 캡슐화한다. 외부에서 보면 어떤 객체가 무슨 일을 하는지 알 수 없다. 그저, 매서드를 호출하면 해당 요청이 처리된다는 사실만 알 수 있다.
주로 다음과 같은 4가지의 요소로 이루어져 있다.
Command Pattern을 적용한 만능 리모컨의 코드는 다음과 같다.
//Command
public interface Command{
public void execute();
public void undo();
}
이는 Command클래스이다. 리모컨의 버튼이 눌렸을 때, 어떤 버튼이 눌렸는지에 따른, 해야할 일들을 담고있다.
예를 들어서 조명을 켤 때 필요한 커맨드와 간단한 리모컨을 구현해보자.
//Concrete Command
public class LightOnCommand implements Command{
Light light;
public LightOnCommand(Light light){ //어떤 특정한 조명을 켤건지. ex) 거실조명 등
this.light = light;
}
public void execute(){ //light객체에 있는 on()을 호출함
light.on();
}
public void undo(){
light.off();
}
}
// Invoker
public class SimpleRemoteControl{
Command slot; //Command를 저장할 슬롯
public SimpleRemoteControl() {}
public void SetCommand(Command command){
slot = command;
}
public void buttonWasPressed(){ //버튼을 누르면 발동되는 메서드. 슬롯에 연결된 커맨드 객체의 execute()만 호출한다.
slot.execute();
}
}
// Receiver는 Light이다
이제, 리모컨을 사용해서 불을 켜기 위해서는, SetCommand() 매서드를 통해서 LightOnCommand 객체를 리모컨 객체의 slot에 지정하고, 리모컨의 버튼을 누르면 된다.