Design pattern study 6 command pattern

Post on 05-Aug-2015

100 views 3 download

Transcript of Design pattern study 6 command pattern

DESIG

N PATT

ERN STU

DY 6.

COMMAND PATT

ERN

호출 캡슐화

INDEX

1. COMMAND 패턴 소개2. COMMAND 패턴 정의3. UNDO COMMAND

• 본 PPT 는 Design Patterns Study 를 위해 작성되었습니다 .

• Study 에 사용한 교재는 한빛미디어에서 나온• [Head First Desgin Patterns] 을 사용하였습니다 .

• Written by 서울시립대 이희태 For study withNHN NEXT2 기 조현호서울시립대 이희태

1. COMMAND 패

턴 소개

안녕하십니까 ?

저희가 새로 개발한 홈 오토메이션 리모컨의 API 디자인을 의뢰하고자 합니다 .

저희 회사에서 개발 중인 최신형 리모컨 시제품을 동봉해 드리겠습니다 . 이 리모컨에는 일곱 가지 프로그래밍이 가능한 슬롯과 각 슬롯에 대한 ON/OFF

스위치가 있습니다 . 각 슬롯은 다양한 가정용 기기에 연결할 수 있습니다 .

리모컨에는 작업취소 버튼도 장착되어 있습니다 .

그리고 조명 , 팬 , 욕조 , 오디오를 비롯한 장비들을 제어하기 위한 용도로 다양한 업체에서 공급받은 자바 클래스들을 CD 에 동봉해서 보내드립니다 . 각 슬롯을 한 가지 기기 또는 하나로 엮어 있는 일련의 기기들에 할당할 수 있도록 리모컨을 프로그래밍하기 위한 API 를 제작해주시길 부탁 드립니다 .

여러분께서 설계하신 디자인을 하루 빨리 볼 수 있기를 기대하고 있겠습니다 .

건승을 기원합니다 .

빌 “ X – 10” 톰슨 , CEO

디자인 의뢰가 들어왔네요 .

동봉된 리모컨을 살펴봅시다 .

1 번 슬롯에 연결되는 가전제품 제어

2 번 슬롯에 연결되는 가전제품 제어

. . .

버튼들이 쭉 나열된다 .

7 가지 프로그래밍이 가능한 슬롯 . 각 슬롯에 원하는 제품을 연결한 후 우측의 버튼으로 조작할 있다 .

Undo 버튼 : 마지막으로 누른 버튼에 대한 명령 취소

제어할 수 있는 제품의 이름이 등록

CD 에 동봉된 클래스들을 살펴보자 .

on()off()dim()

CeilingLight

on()off()

OutdoorLight

on()off()setInputChannel()setVolume()

TV

on()off()setCD()setDvd()setRadio()setVolume()

Stereoup()down()lightOn()lightOff()

GarageDoor

high()medium()low()off()getSpeed()

CeilingFan

setDuskTime()setDawnTime()manualOn()manualOff()

GardenLight

on()off()

Light

jetsOn()jetsOff()Circulate()setTemperature()

Hottub

waterOn()waterOff()

Sprinkler

openValue()closeValue()

FaucetControl

리모컨 API 디자인 설계

지금 바로 위의 가전제품 클래스들을 리모컨에 부착하도록 설계하면 어떨까 ?

문제점1. 바뀌는 부분을 따로 캡슐화하지 않았다 .

2. 상위 클래스가 아닌 구체적인 클래스들에 의존하고 있다 .

3. 리모컨에 부착하는 구체적인 가전제품 클래스들이 새로 추가 , 변경될 때마다 리모컨의 코드를 고쳐야 한다 .

4. 가전제품에 따라 리모컨 on/off 버튼에 해당되는 메소드 호출이 다 달라야만 한다 .

5. 리모컨에서 가전제품 클래스에 대해 정보은닉이 되고 있지 않는다 .

즉 ,리모컨의 버튼과 가전제품의 특정 기능 (ex. On, off) 들이 전혀 분리되어 있지 않다 . Client 에서 특정 작업 요청이 이루어질 때 그 요청 호출을 캡슐화할 필요가 있다 .

Command Pat-tern 을 사용한다 !

레스토랑에 잠깐 들려보자…

JAVA Restaurant

연어스테이크 ,카바 (cava)

createOrder() takeOrder()

OrderUp()

주문서(Order 객체 )

makeSteak()makeWine()

연어스테이크 ,카바 (cava)

웨이트리스와 요리사가 구분되어있다 .

이 둘은 Order 객체 – 주문서 – 를 통해서 소통할 뿐이다 .

요리사는 요리에 필요한 정보만 가지고 있다 . 요리를 하지 주문을 받지는 않는다 .

웨이트리스는 주문서를 식사를 준비시킨다 .요리를 하지 않는다 .

2.COMMAND PA

TTERN

정의

exe-cute

()

exe-cute

()

Client Command

Command

Invoker

Receiver

createCommandOb-ject()

Invoker.setCommand(Command sth)

set-Com-mand()

execute()

action1()action2()

action1()action2() 의 결과물

JAVA Restaurant Command Pattern

손님 Client 객체

주문서 Command 객체takeOrder() setCommand()

웨이트리스 Invoker 객체orderUp() execute()

주방장 Receiver 객체

레스토랑과 커맨드패턴의 비교

COMMAND PATTERN 이란 ?

Def : 커맨드 패턴을 이용하면 요구 사항을 객체로 캡슐화할 수 있으며 , 매개 변수를 써서 여러 가지 다른 요구 사항을 집어 넣을 수 있다 . 또한 요청 내역을 큐에 저장하거나 로그로 기록할 수도 있으며 , 작업 취소 기능도 지원 가능하다 .

UML 다이어그램

+setCom-mand()

커맨드 객체에게 Exe-cute() 를 실행하도록 요청 <Interface>

매개변수로 command 객체를 받음

ConcreteCommand 를 생성한 후 그 객체에 특정 Receiver 를 넣어줌

구현된 Excetute() 메소드에서는 re-ceiver 의 메소드 (Action()) 를 호출하여 요청된 작업을 수행 ( 호출의 캡슐화 )

command Interface

Receiver

Invoker

NoCom-mandNoCommand 가 없다면 ?

☞ NoCommand 는 on/offButtonWasPushed() 메소드를 더 간단하게 만든다 .

setCommand()

public void setCommand(int slot, Command onCommand, Com-mand offCommand)

- Invoker( = RemoteControl) 의 각 slot 에 concreteCommand 객체를 등록하는 메소드

RemoteControlTest(1)

RemoteControlTest(2)

3. UNDO C

OMMAND

작업취소 (UNDO) 버튼 ?

바로 이전 상태로 되돌린다 !

Interface 에 undo() 메소드를 선언해준다 .

concreteCommand 객체에서 undo() 메소드를 구현한다 . On Command 객체라면 -> off 로 , Off Command 객체라면 On 으로 작업취소 명령을 정의해준다 .

Undo() 가 추가된 Command 객체

Invoker

undoCommand 객체를 멤버변수로 넣어주고…

여기에도 noCommand 대입

사용자가 버튼을 누르면 우선 해당 Command를 실행한 뒤 (=execute() 호출한 후 ), 바로 그 객체의 레퍼런스를 undoCommand 변수에 할당해준다 .

사용자가 undoButton 을 누르면 현재 저장된 undo-Command 객체의 undo() 메소드를 호출한다 .그러면 마지막으로 했던 작업이 취소된다 .

RemoteControlTest, Console 출력

livingRoomLightOn.exe-cute()livingRoomLightOff.exe-cute()livingRoomLightOff.undo()

livingRoomLightOff 에서의 작업취소

Q/A

Q1. 항상 리시버가 필요한가요 ? 커맨드 객체에서 execute() 를 구현해 버리면 안되나요 ?

ans) 일반적으로 리시버에 있는 행동을 호출하는 “더미” 커맨드 객체를 만든다 . 하지만 요구사항의 전부는 아니더라도 대부분을 요구하는 “스마트” 커맨드 객체를 만드는 경우도 자주 볼 수 있다 . 물론 커맨드객체에서 대부분의 행동을 처리해도 된다 . 하지만 그렇게 하면 여기에서 우리가 했던 수준으로 인보커와 리시버를 분리시키는 것이 불가능해지고 , 리시버를 이용해서 커맨드를 매개변수화하는것도 할 수 없다 .

Q2. 작업 취소를 할 때 히스토리 기능은 어떻게 구현할 수 있나요 ? 즉 , UNDO버튼을 여러 번 누를 수 있도록 하려면 어떻게 해야 하나요 ?

ans) 간단하다 . 앞에서는 undoCommand 에 마지막으로 실행한 커맨드에 대한 레퍼런스를 그냥 대입했는데 , 여기서는 스택을 이용하여 이전에 실행한 커맨드를 순서대로 저장하면 된다 . 그리고 나서 사용자가 undo 버튼을 누를 때마다 스택의 맨 위에서부터 항목을 꺼내서 undo() 메소드를 호출하기만 하면 된다 .

Than

k yo

u!