문제 제기

만능 리모컨 회사에서 여러 물품에 블루투스 리모컨 시스템을 사용할 수 있는 환경을 만들어달라고 의뢰를 해왔다.
의뢰를 들어온 물품 Object 들의 시그니쳐는 다음과 같이 제공되었다.

물론 더 많겠지만 일단 4개만 해보자.

 

- 공통된 Method가 존재하기도 하는데 대부분 겹치지않는다. 공통된 행위가 없어서 Starategy 패턴으로 뺄수도 없을것 같고 이럴땐 어떻게 해야할까?

 

커맨드 패턴 살펴보기

- 가장 먼저 커맨드 패턴의 클래스 다이어그램부터 살펴보자

 

- 클래스 다이어그램에는 가장 핵심적인 요소 4가지가 있다. Client, Invoker, Command, Receiver 이다.

- 대소 관계로 비교하기 좀그렇지만 Client는 {Invoker, Command, Receiver}를 다 가지고 있다.
그리고 클라이언트의 요청에따라 Invoker > Command > Receiver 순서로 트리거 된다. 그러나 그전에 클라이언트에서 해주어야 할 작업이 있다. 이 작업을 순서대로 풀어 써 보자면

1) Client는 가장 먼저 Receiver를 생성 후 Command에 넘겨 Command를 생성해준다.
2) 다음으로 클라이언트는 CommandInvoker에게 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객체로 구현하므로써, 매개변수로써 여러가지 다른 리시버들을 실행 시켰다.

+ Recent posts