문제 제기
만능 리모컨 회사에서 여러 물품에 블루투스 리모컨 시스템을 사용할 수 있는 환경을 만들어달라고 의뢰를 해왔다.
의뢰를 들어온 물품 Object 들의 시그니쳐는 다음과 같이 제공되었다.
- 공통된 Method가 존재하기도 하는데 대부분 겹치지않는다. 공통된 행위가 없어서 Starategy 패턴으로 뺄수도 없을것 같고 이럴땐 어떻게 해야할까?
커맨드 패턴 살펴보기
- 가장 먼저 커맨드 패턴의 클래스 다이어그램부터 살펴보자
- 클래스 다이어그램에는 가장 핵심적인 요소 4가지가 있다. Client, Invoker, Command, Receiver 이다.
- 대소 관계로 비교하기 좀그렇지만 Client는 {Invoker, Command, Receiver}를 다 가지고 있다.
그리고 클라이언트의 요청에따라 Invoker > Command > Receiver 순서로 트리거 된다. 그러나 그전에 클라이언트에서 해주어야 할 작업이 있다. 이 작업을 순서대로 풀어 써 보자면
1) Client는 가장 먼저 Receiver를 생성 후 Command에 넘겨 Command를 생성해준다.
2) 다음으로 클라이언트는 Command를 Invoker에게 Set 해주고 Invoker를 생성해준다
3) client는 필요할때 Invoker에게 invoke()를 요청한다.
4) 이렇게 되면 Invoker.Invoke() -> Command.execute() -> receiver.action() 순으로 실행된다.
이를 그림으로 표현 한 것이다.
간단한 리모컨에 커맨드 패턴 끼얹기
- 자 위와 같이 간단한 On/Off 버튼이 있다고 먼저 가정해보자.
- 웜업으로 아까 받은 여러개의 클래스 다이어그램에서 Light의 On()과 Garage의 Up()만 구현해보자.
1) 각각 Receiver를 구현해보자.
public class GarageDoorReceiver {
public void up() {
System.out.println("garage up");
}
public void down() {
}
public void stop() {
// TODO Auto-generated method stub
}
public void lightOn() {
}
public void lightOff() {
}
}
public class GarageDoorReceiver {
public void up() {
System.out.println("garage up");
}
public void down() {
}
public void stop() {
// TODO Auto-generated method stub
}
public void lightOn() {
}
public void lightOff() {
}
}
2) Command Interface를 만들고, Command 구현체를 각각 만들어주자
public interface Command {
public void execudte();
}
public class LightonCommand implements Command{
LightReceiver light;
public LightonCommand(LightReceiver light) {
this.light = light;
}
@Override
public void execudte() {
light.on();
}
}
public class GarageCommand implements Command{
GarageDoorReceiver gar;
public GarageCommand(GarageDoorReceiver gar) {
this.gar = gar;
}
@Override
public void execudte() {
gar.up();
}
}
3) 위 두가지 Command를 실행해줄 SimpleRemotecontrol Invoker 를 만들어보자
public class SimpleRemotecontrol {
Command com;
public SimpleRemotecontrol() {
// TODO Auto-generated constructor stub
}
public void setCom(Command com) {
this.com = com;
}
public void btnPressed() {
com.execudte();
}
}
4) 한번 Client (메인함수) 에서 실행시키고 결과를 보자.
public class RemoteControlTest {
public static void main(String[] args) {
SimpleRemotecontrol remote = new SimpleRemotecontrol();
LightReceiver light = new LightReceiver();
LightonCommand lightOnCommand = new LightonCommand(light);
remote.setCom(lightOnCommand);
remote.btnPressed();
GarageDoorReceiver ga = new GarageDoorReceiver();
GarageCommand garageCommand = new GarageCommand(ga);
remote.setCom(garageCommand);
remote.btnPressed();
}
}
- 간단하게 커맨드 패턴을 활용하여 두가지 Light, Garage Receiver를 구현해보았다.
- 위 소스의 클래스 다이어그램은 아래와 같이 그릴 수 있다.
커맨드 패턴의 정의
- 커맨트 패턴의 공식적인 정의는 다음과 같다.
커맨드 패턴
커맨드 패턴을 이용하면 요구사항을 객체로 캡슐화 할 수 있으며, 매개변수를 써서 여러가지 다른 요구사항을 집어넣을수도 있다. 또한 요청내역을 큐에저장하거나, 로그로 기록할 수도 있으며, 작업취소 기능도 지원합니다.
-간단한 커맨드 패턴에 작업취소등 추가적인 작업은 다음시간에 해보겠다.
- 결국 커맨드 패턴이란, 일련의 행동을 특정 리시버로 연결시켜 요구사항을 커맨드로 캡슐화 한것이다. 외부에서 볼때는 어떤 리시버가 실행되는지, 어떤 객체가 리시버역할을하는지, 그 리시버에서 실제로 어떤 수행을 하는지 알 수 없다. 그냥 execute()가 실행되면 리시버가 실행된다는 것만 알 수 있을뿐이다. 또한 우리는 Receiver를 Command객체로 구현하므로써, 매개변수로써 여러가지 다른 리시버들을 실행 시켰다.
'To be Developer > DesignPatterns' 카테고리의 다른 글
6-2. Command Pattern (Remotecontrol Upgrade) (0) | 2020.01.14 |
---|---|
5.Singleton Pattern (0) | 2020.01.07 |
4-2 Factory Pattern (Abstract Factory Pattern) (0) | 2020.01.05 |
4-1.Factory Pattern (Factory Method Pattern) (0) | 2020.01.04 |
3.Decorator Pattern (0) | 2020.01.02 |