Command Pattern 커맨드 패턴을 액션스크립트로 컨버팅. 두 번째 – Head First Design Pattern
by 세계의끝 on 8.09, 2009, under Design Pattern
지난 포스트에서는 간단한 형태의 커맨드 패턴에 대해 살펴보았습니다. 이 포스트는 여러가지 커맨드 객체를 조합하여 실제 사용될법한 커맨드 패턴 리모컨을 만들어 보겠습니다.
지난 포스트에서 Light 구상객체를 만들어, LightOnCommand 객체로 감싸고, LightOnCommand 객체를 SimpleRemote 에 setCommand() 메서드를 이용하여 할당 한 후, 필요할 때마다 호출하는것 까지 해 보았습니다.
커맨드 패턴은 이렇게 구상 객체의 메서드를 직접 호출하지 않고, 구상객체를 감싸고 있는 커맨드 객체를 호출하여 캡슐화 한 것입니다. 이렇게 캡슐화를 하게 되면, 새로운 구상객체가 생겨도 리모컨 객체의 코드의 변경 없이 각 기능별로 ICommand 인터페이스를 구현한 커맨드 객체를 만들고 리모컨 객체에 할당하여 호스트코드에서 모두 동일한 명령어로 구상객체의 메서드를 호출할 수 있게되는 장점을 누릴 수 있게 됩니다.
지난 포스트에서는 Light 구상객체를 다뤄보았으니, 이번에는 좀 다른 구상객체를 살펴보겠습니다.
먼저 지난번과 같은 ICommand 인터페이스 입니다.
0 1 2 3 4 5 6 | package { public interface ICommand { function execute():void } } |
Stereo 클래스는 오디오 시스템을 표현하는 구상 클래스 입니다. 단순히 불을 켜고 끄는것이 아니라 여러 가지 기능을 수행하고 있습니다.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | package { public class Stereo { private var location:String; public function Stereo( $location:String ) { this.location = $location } public function on():void { trace( location , "스테레오 켬" ) } public function off():void { trace( location , "스테레오 끔" ) } public function setCD():void { trace( location , "스테레오에 CD 넣음" ) } public function setDVD():void { trace( location , "스테레오에 DVD 넣음" ) } public function setRadio():void { trace( location , "스테레오에 라디오 켬" ) } public function setVolume( $volume:int ):void { trace( location , "스테레오 볼륨을", $volume, "으로 조정" ) } } } |
StereoOnWithCDCommand 클래스는 ICommand 를 구현하는 커맨드 객체 클래스 입니다.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package { public class StereoOnWithCDCommand implements ICommand { private var stereo:Stereo; public function StereoOnWithCDCommand( $stereo:Stereo ) { this.stereo = $stereo; } public function execute():void { stereo.on(); stereo.setCD(); stereo.setVolume( 11 ); } } } |
execute() 메서드를 호출하면 스테레오시스템을 켜고, CD를 넣고, 볼륨을 11로 설정하게 됩니다.
StereoOffCommand 는 execute() 메서드 안에 stereo.off() 가 있다는 것만 제외하면 StereoOnWithCDCommand 클래스와 동일한 클래스 입니다.
StereoOffCommand 클래스를 포함한 전체 코드는 아래에서 다운로드 받을 수 있는 링크가 있습니다.
그럼 리모컨 클래스를 어떻게 변했을까요?
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | package { public class RemoteControl { private var onCommands:Array; private var offCommands:Array; public function RemoteControl() { onCommands = new Array(); offCommands = new Array(); var noCommand:ICommand = new NoCommand(); for ( var i:int = 0; i < 7; i++ ) { onCommands[ i ] = noCommand offCommands[ i ] = noCommand } } public function setCommand( $slot:int, $onCommand:ICommand, $offCommand:ICommand ):void { onCommands[ $slot ] = $onCommand; offCommands[ $slot ] = $offCommand; } public function onButtonWasPushed( $slot:int ):void { onCommands[ $slot ].execute(); } public function offButtonWasPushed( $slot:int ):void { offCommands[ $slot ].execute(); } public function toString():String { var str:String = "\n------ Remote Control -------" for ( var i:int = 0; i < onCommands.length; i++) { str += "\n[slot " + i + "] " + onCommands[i] + " " + offCommands[i] } return str } } } |
SimpleRemoteControl 에 비해서 코드가 많이 추가되었지만 하는일은 변함이 없습니다. 이번에는 다뤄야 하는 커맨드객체의 숫자가 여러개 이므로 배열로 관리를 하고 있고, on 버튼과 off 버튼을 따로 누르도록 만들었습니다. 어떤 구상객체를 담고 있는 커맨드 객체라 하더라도 리모컨 객체는 아무생각없이 execute() 만 호출하면 되는 것이죠.
호스트 코드는 컨버팅 대상인 자바코드 전체를 번역하였기 때문에 내용이 다소 깁니다만, Stereo 객체만을 눈여겨 보시면 되겠습니다.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | package { import flash.display.Sprite; public class Main extends Sprite { public function Main():void { var remoteControl:RemoteControl = new RemoteControl(); var livingRoomLight:Light = new Light( "거실" ); var kitchenLight:Light = new Light( "주방" ); var cellingFan:CeilingFan = new CeilingFan( "거실" ) var garageDoor:GarageDoor = new GarageDoor( "" ); var stereo:Stereo = new Stereo( "거실" ) var livingRoomLightOn:LightOnCommand = new LightOnCommand( livingRoomLight ); var livingRoomLightOff:LightOffCommand = new LightOffCommand( livingRoomLight ); var kitchenLightOn:LightOnCommand = new LightOnCommand( kitchenLight ); var kitchenLightOff:LightOffCommand = new LightOffCommand( kitchenLight ); var ceilingFanOn:CeilingFanOnCommand = new CeilingFanOnCommand( cellingFan ); var ceilingFanOff:CeilingFanOffCommand = new CeilingFanOffCommand( cellingFan ); var garageDoorUp:GarageDoorUpCommand = new GarageDoorUpCommand( garageDoor ); var garageDoorDown:GarageDoorDownCommand = new GarageDoorDownCommand( garageDoor ); var stereoOnWithCD:StereoOnWithCDCommand = new StereoOnWithCDCommand( stereo ); var stereoOff:StereoOffCommand = new StereoOffCommand( stereo ); remoteControl.setCommand( 0, livingRoomLightOn, livingRoomLightOff ); remoteControl.setCommand( 1, kitchenLightOn, kitchenLightOff ); remoteControl.setCommand( 2, ceilingFanOn, ceilingFanOff ); remoteControl.setCommand( 3, stereoOnWithCD, stereoOff ); trace( remoteControl.toString() ); remoteControl.onButtonWasPushed( 0 ); remoteControl.offButtonWasPushed( 0 ); remoteControl.onButtonWasPushed( 1 ); remoteControl.offButtonWasPushed( 1 ); remoteControl.onButtonWasPushed( 2 ); remoteControl.offButtonWasPushed( 2 ); remoteControl.onButtonWasPushed( 3 ); remoteControl.offButtonWasPushed( 3 ); } } } |
Stereo 객체를 생성하고 두 개의 커맨드 객체 StereoOnWithCDCommand( stereo ) 와 StereoOffCommand( stereo ) 에 넣어, setCommand 메서드를 이용해서 커맨드 객체를 러퍼런스로 저장하였습니다.
이번 리모컨은 on 버튼과 off 버튼이 따로 있는 리모컨 이므로 사용할 때도 각각의 메서드를 호출하게 됩니다.
실행 결과는 다음과 같습니다.
—— Remote Control ——-
[slot 0] [object LightOnCommand] [object LightOffCommand]
[slot 1] [object LightOnCommand] [object LightOffCommand]
[slot 2] [object CeilingFanOnCommand] [object CeilingFanOffCommand]
[slot 3] [object StereoOnWithCDCommand] [object StereoOffCommand]
[slot 4] [object NoCommand] [object NoCommand]
[slot 5] [object NoCommand] [object NoCommand]
[slot 6] [object NoCommand] [object NoCommand]
거실 불 켜짐
거실 불 꺼짐
주방 불 켜짐
주방 불 꺼짐
거실 선풍기 속도 높음
거실 선풍기 끔
거실 스테레오 켬
거실 스테레오에 CD 넣음
거실 스테레오 볼륨을 11 으로 조정
거실 스테레오 끔
Blog under the Creative Commons Attribution-NoDerivs 3.0 License