top bar

글 목록

2014년 7월 5일 토요일

커맨드 패턴 (command pattern) 2

이전 포스트에서 정리했던 커맨드패턴의 적용 사례에 대해 이야기하고자 한다.

A라는 회사가 IT 솔루션 업체인 B에게 홈 오토메이션 리모콘의 API 디자인을 요청했다.
A회사가 넘긴 리모콘 시제품엔 7개의 프로그래밍이 가능한 슬롯이 있으며, 각 슬롯엔 ON/OFF 기능이 있다.

대략 이렇게 생겼다.



각 슬롯엔 전등켜기/끄기 , 선풍기 켜기/끄기, 차고 열기/닫기 등의 기능들을 집어넣으려고하는데... 커맨드패턴을 적용시켜보자.

먼저 모든 커맨드(행동)들은 다음과같은 인터페이스를 구현한다.



전등의 불을켜는 행동을하는 커맨드 클래스의 구상클래스는 아래와같다.



이부분에서 마음에안드는 부분이있지만... 이 포스팅 말미에 털어놓겠다...
위 코드의 5번라인의 Light 클래스는 실제로 특정작업을 처리하는 로직이 담겨있는 리시버(Receiver) 객체이다.
Command 인터페이스를 구현한 이 구상클래스의 execute메서드는 해당 커맨드객체가 가지고있는 리시버의 실제 수행메서드 on()을 호출하는 역할을 한다.

리시버는 다음과같이 작성한다.



실제로 특정작업을 수행하는 메서드 on()과 off()가 작성되어있다. 
주방또는 거실등 의 전등을 구분하기위해 location 멤버변수를 가지고있다.

인보커인 RemoteControl 클래스는 아래와같다.



RemoteControl 클래스에는 7개의 슬롯이있으며, 각 슬롯마다 setCommand 메서드를 이용해 
onCommand, offCommand 클래스를 할당할수있다.

on동작은 onButtonWasPushed메서드를 호출하고, off동작은 offButtonWasPushed메서드를 호출하며, 각 메서드는 해당슬롯의 커맨드 객체의 execute 메서드를 호출하게된다.

모든 준비는 끝났고, 클라이언트 코드를 작성해보자.



전등을 키고끄는 동작을하는 리시버인 Light 클래스외에, 차고의 문을 열고닫는 GarageDoor 클래스, 오디오를 컨트롤하는 Stereo 클래스등 기타 리시버를 작성하였다. 각 리시버의 동작마다 커맨드클래스를 작성하고, 해당하는 리시버를 생성자의 매개변수로 넘겨준다. (20~29 line)

그리고 11라인에 생성한 인보커객체인 remote 인스턴스의 setCommand 메서드를 이용해 각슬롯마다 해당기능의 on/off 커맨드 객체를 넘겨준다. 여기서는 0,1,2,3 슬롯만 커맨드 객체를 할당하였다.

37라인~40라인은 리모콘의 버튼을 누르는 동작이다. 결과는 다음과같다.







UML로 정리하자.



아.. 정리가 안된다..moon_and_james-57

무튼, 맘에 안드는 부분은 바로 리시버의 동작마다 커맨드클래스를 구현해야한다는것이다. 아래와같이 Stereo 리시버 객체는 다음과같은기능들이있다.



on 과 off 외에 setCd , setDvd , setRadio , setVolume 등의 기능이있는데, 이 기능들 하나하나마다 커맨드 클래스를 작성해야한다. 꼭이래야 할까? 최초 명령을 내리는 객체와 실제로 말단의 로직을 수행하는 객체사이의 Loose coupling 으로 인한 유연성이 확보되어 한결 유지보수가 용이해졌지만, 제한없이 늘어나는 커맨드 클래스는 분명 보기 좋지 많은 않다.....

좀더 공부해봐야겠다는 결론으로 본 포스팅을 마무리한다.

댓글 없음:

댓글 쓰기