59
객체지향 설계와 패턴 객체지향 설계와 패턴 Lecture #13: 행위 패턴(2) Eun Man Choi [email protected]

객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

  • Upload
    others

  • View
    4

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

객체지향 설계와 패턴

Lecture #13: 행위 패턴(2)

객체지향 설계와 패턴

Lecture #13: 행위 패턴(2)

Eun Man [email protected]

Page 2: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

학습 목표

l 옵서버 패턴

l 상태 패턴

l 커맨드 패턴

l 실습 문제

2

l 옵서버 패턴

l 상태 패턴

l 커맨드 패턴

l 실습 문제

Page 3: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

Pattern #16 – 옵서버 패턴

한 객체에 의하여 영향 받는 객체들을 정리하는데사용

l 패턴 요약l 단일 객체가 영향 받는 객체 집합에 대하여 같은 이름의 메소드를 호출하

여 구현l 관찰 대상 객체가 관찰하는 객체가 몇 개인지 어떤 클래스인지 모름

3

Page 4: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴: 동기

당신은 기업정보 입출력 프로그램을 개발 중이다. 이 프로그램을이용하여 사용자들은 DB에 저장되어 있는 기업정보(월 판매액, 매출증가량, …)를 여러 가지 형태(도표, 꺾은선그래프, 막대그래프,..)로볼 수 있어야 한다. 또한 관리자들이 특정 기업정보를 갱신한다면해당 정보를 보여주고 있는 모든 View들은 변경된 정보를 다시반영하여 보여주어야 한다. 기업정보(Model)과 보여주는화면(View)과의관계를어떻게설계할것인가?

당신은 기업정보 입출력 프로그램을 개발 중이다. 이 프로그램을이용하여 사용자들은 DB에 저장되어 있는 기업정보(월 판매액, 매출증가량, …)를 여러 가지 형태(도표, 꺾은선그래프, 막대그래프,..)로볼 수 있어야 한다. 또한 관리자들이 특정 기업정보를 갱신한다면해당 정보를 보여주고 있는 모든 View들은 변경된 정보를 다시반영하여 보여주어야 한다. 기업정보(Model)과 보여주는화면(View)과의관계를어떻게설계할것인가?

4

data 값이변경된다면view-1, view-2 가변경된값을반영하도록

Page 5: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴: 동기

[해결방안]l Model(data)이 변경되면 이를 각 view(화면)들에게 알려줌

l Model은 자신의 정보변경에 대한 notification을 받기를 원하는 뷰들에 대한 레퍼런스를 가지고 있어야 한다.

Modela:45b:35c:20

View-1: PieChart

View-2: BarChart

•값변동시 Model은 view-1, view-2에변동사실을통지함

[해결방안]l Model(data)이 변경되면 이를 각 view(화면)들에게 알려줌

l Model은 자신의 정보변경에 대한 notification을 받기를 원하는 뷰들에 대한 레퍼런스를 가지고 있어야 한다.

5

•값변동시 Model은 view-1, view-2에변동사실을통지함

• Model에는뷰들을등록하고관리할수있는인터페이스가필요- Attach(View *): 통지받을 view 등록- Detach(View *): 통지받을 view 등록해제- Notify(): 변경발생시등록된 view들에게통보

• Model에는뷰들을등록하고관리할수있는인터페이스가필요- Attach(View *): 통지받을 view 등록- Detach(View *): 통지받을 view 등록해제- Notify(): 변경발생시등록된 view들에게통보

Page 6: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴: 동기

[해결방안] -2l 정보변경 통보를 받은 뷰들은 모델l에게서 변경된 정보를 얻어옴

l 각 뷰들은 자신이 필요로 하는 모델에 대한 레퍼런스를 가지고 있으며, 모델에게원하는 정보를 얻어 올 수 있다.

Modela:45b:35c:20

View-1: PieChart

View-2: BarChart

GetValues

GetValues

[해결방안] -2l 정보변경 통보를 받은 뷰들은 모델l에게서 변경된 정보를 얻어옴

l 각 뷰들은 자신이 필요로 하는 모델에 대한 레퍼런스를 가지고 있으며, 모델에게원하는 정보를 얻어 올 수 있다.

6

Page 7: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴: 동기

[해결방안] -3

7

변화발생Notify()

Page 8: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴: 동기

[해결방안] -4l Model class도 향후 확장을 고려하여 class hierarchy로 구성l Observer pattern에서는 통지하는 역할을 Subject, 통지 받는 역할을 Observer

라고 얘기함.

Observer

Subject

8

Page 9: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴

l 의도l 한 객체의 상태가 변하면 관련된 다른 모든 객체들이 해당 상태변화를 알

수 있도록 객체들 간의 one-to-many 의존관계를 정의한다.

l 별칭l Dependents, Publish-Subscribe

l 적용 범위l 시스템의 한 부분이 다른 부분에 의존적일 때, 양자를 개별적인 객체로

만들고 Observer pattern을 적용하면, 독립성과 재사용성을 높일 수 있다.

l 한 객체의 상태가 변경되면 다른 객체들도 따라 변경될 필요가 있을 때, 그리고, 얼마나 많은 객체들이 따라서 변경되어야 하는지 알 필요가 없을때.

l 변경을 알리는 객체와 변경을 통지 받는 객체간의 연결강도를 줄일 때

l 의도l 한 객체의 상태가 변하면 관련된 다른 모든 객체들이 해당 상태변화를 알

수 있도록 객체들 간의 one-to-many 의존관계를 정의한다.

l 별칭l Dependents, Publish-Subscribe

l 적용 범위l 시스템의 한 부분이 다른 부분에 의존적일 때, 양자를 개별적인 객체로

만들고 Observer pattern을 적용하면, 독립성과 재사용성을 높일 수 있다.

l 한 객체의 상태가 변경되면 다른 객체들도 따라 변경될 필요가 있을 때, 그리고, 얼마나 많은 객체들이 따라서 변경되어야 하는지 알 필요가 없을때.

l 변경을 알리는 객체와 변경을 통지 받는 객체간의 연결강도를 줄일 때

9

Page 10: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴

l Structure

10

Page 11: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴

l 참여요소l Subject

• 통지 받을 Observer 객체들을 알고 있다.• Observer 객체들을 추가하고 삭제하는 interface를 제공한다.

–Attach(), Detach()l Observer(View)

• 상태 변경 통지를 받을 interface를 정의한다. - Update()l ConcreteSubject(Model)

• ConcreteObserver 객체들이 필요로 하는 정보를 가지고 있다.• 정보가 변경되면 등록된 Observer 객체들에게 통보한다.

l ConcreteObserver(BarChart, PieChart)• 필요한 정보를 가지고 있는 ConcreteSubject 객체를 알고 있다.• 상태 변경 통지를 받으면 ConcreteSubject 객체에게 변경된 정보를

얻어온다.

l 참여요소l Subject

• 통지 받을 Observer 객체들을 알고 있다.• Observer 객체들을 추가하고 삭제하는 interface를 제공한다.

–Attach(), Detach()l Observer(View)

• 상태 변경 통지를 받을 interface를 정의한다. - Update()l ConcreteSubject(Model)

• ConcreteObserver 객체들이 필요로 하는 정보를 가지고 있다.• 정보가 변경되면 등록된 Observer 객체들에게 통보한다.

l ConcreteObserver(BarChart, PieChart)• 필요한 정보를 가지고 있는 ConcreteSubject 객체를 알고 있다.• 상태 변경 통지를 받으면 ConcreteSubject 객체에게 변경된 정보를

얻어온다.

11

Page 12: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴

l 협동관계

12

Page 13: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴

l 결과l Subject객체와 Observer객체간의 coupling을 줄임

• Subject 객체는 단지 Observer 객체 list를 가지고 있다는 정도만 알면 된다.

• Subject class와 Observer class가 서로 독립적으로 변경 및 확장될수 있다.

l Broadcast 통신에도 이용 가능• Observer객체들이 원하는 subject객체에 등록하지 않고, subject의

상태가 변화되면 전체 객체들에게 상태변화를 broadcast함l 예상치 못한 updates 발생 가능

• 관찰자 객체들(Observers) 간에는 상호존재를 인식하지 못하기 때문에, 한 Subject 객체의 상태변화가 전체적으로 어느 정도 만큼의Observer 변화 비용이 드는지 알지 못함

l 결과l Subject객체와 Observer객체간의 coupling을 줄임

• Subject 객체는 단지 Observer 객체 list를 가지고 있다는 정도만 알면 된다.

• Subject class와 Observer class가 서로 독립적으로 변경 및 확장될수 있다.

l Broadcast 통신에도 이용 가능• Observer객체들이 원하는 subject객체에 등록하지 않고, subject의

상태가 변화되면 전체 객체들에게 상태변화를 broadcast함l 예상치 못한 updates 발생 가능

• 관찰자 객체들(Observers) 간에는 상호존재를 인식하지 못하기 때문에, 한 Subject 객체의 상태변화가 전체적으로 어느 정도 만큼의Observer 변화 비용이 드는지 알지 못함

13

Page 14: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴

l 구현l Mapping subjects to their observers

• Subject 객체가 Observer 객체들을 관리하는 방식은?– The simplest way: Subject 객체가 Observer reference를 포함

• Subject 객체가 많고 Observer객체가 적다면 Subject가 가지고 있을Observer references가 중복 되어 메모리 낭비가 발생한다(대안: Hash Table).

l Observing more than one subject• 필요로 하는 정보의 종류에 따라, 한 Observer 객체가 통지를 원하는 Subject

객체를 여러 개 둘 수 있다.• 변경통지가 왔을 때 어떤 Subject 객체에서 온 통지인지 확인은?

– Update() 함수의 인자로 통지를 보내는 Subject 객체를 넘김

l Who triggers the update?1. Subject의 내부 변수 값 변경 시 자동으로 Notify() 호출하기2. Client 에서 Notify() 함수를 직접 호출하기

l 구현l Mapping subjects to their observers

• Subject 객체가 Observer 객체들을 관리하는 방식은?– The simplest way: Subject 객체가 Observer reference를 포함

• Subject 객체가 많고 Observer객체가 적다면 Subject가 가지고 있을Observer references가 중복 되어 메모리 낭비가 발생한다(대안: Hash Table).

l Observing more than one subject• 필요로 하는 정보의 종류에 따라, 한 Observer 객체가 통지를 원하는 Subject

객체를 여러 개 둘 수 있다.• 변경통지가 왔을 때 어떤 Subject 객체에서 온 통지인지 확인은?

– Update() 함수의 인자로 통지를 보내는 Subject 객체를 넘김

l Who triggers the update?1. Subject의 내부 변수 값 변경 시 자동으로 Notify() 호출하기2. Client 에서 Notify() 함수를 직접 호출하기

14

Page 15: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴

l Dangling references to deleted subjects• 특정 Subject 객체가 소멸된다면, 이 객체를 reference하고 있는

Observer 객체들은 어떻게 할 것인가?• 소멸되는 Subject 객체에 등록된 Observer들에게 Subject가 소멸됨

을 통지해주어야 함l Making sure Subject state is self-consistent before notification

• Subject 객체의 Notify() 호출되기 전에 Subject 객체 내부 상태 값은일관성을 유지하여야 한다.

l Avoiding observer-specific update protocol• Subject 객체는 단지 Update()호출을 통하여 상태변화만 알려주고,

실제 Subject 객체의 정보를 얻어오는 작업은 ConcreteObserver 객체들이 맡게 되면, 속도 면에서는 조금 손해나 Subject-Observer 간의 연결강도(coupling)은 낮아진다(Pull Model)

• Subject 객체가 상태변화를 통지하기 위하여 Observer 객체들의Update() 함수를 호출할 때 변화된 값도 같이 넘겨준다면 속도는 높일 수 있으나 Subject-Observer 간의 연결강도가 높아진다(Push Model)

l Dangling references to deleted subjects• 특정 Subject 객체가 소멸된다면, 이 객체를 reference하고 있는

Observer 객체들은 어떻게 할 것인가?• 소멸되는 Subject 객체에 등록된 Observer들에게 Subject가 소멸됨

을 통지해주어야 함l Making sure Subject state is self-consistent before notification

• Subject 객체의 Notify() 호출되기 전에 Subject 객체 내부 상태 값은일관성을 유지하여야 한다.

l Avoiding observer-specific update protocol• Subject 객체는 단지 Update()호출을 통하여 상태변화만 알려주고,

실제 Subject 객체의 정보를 얻어오는 작업은 ConcreteObserver 객체들이 맡게 되면, 속도 면에서는 조금 손해나 Subject-Observer 간의 연결강도(coupling)은 낮아진다(Pull Model)

• Subject 객체가 상태변화를 통지하기 위하여 Observer 객체들의Update() 함수를 호출할 때 변화된 값도 같이 넘겨준다면 속도는 높일 수 있으나 Subject-Observer 간의 연결강도가 높아진다(Push Model)

15

Page 16: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴

l Specifying modifications of interest explicitly• 특정 Observer 객체의 경우, Subject 객체의 정보들 중 일부에만 관심이 있을

경우에는?• Observer 객체가 Subject객체의 Attach()를 호출하여 자신을 등록할 때 관심

이 있는 세부정보에 대한 선택도 같이 넘겨야 한다.• Subject 객체의 내부 정보에 변경이 일어났을 때, 해당 항목에 관련된

Observer들에게만 선택적으로 통지한다.

l Encapsulating complex update semantics• 다수의 Subject 객체와 Observer 객체들 간의 관계가 특별히 복잡하고 비효

율적이라면, 변경통보와 변경 값 반영을 전담해주는 ChangeManager 같은별도의 객체를 둘 수 있다.

l Specifying modifications of interest explicitly• 특정 Observer 객체의 경우, Subject 객체의 정보들 중 일부에만 관심이 있을

경우에는?• Observer 객체가 Subject객체의 Attach()를 호출하여 자신을 등록할 때 관심

이 있는 세부정보에 대한 선택도 같이 넘겨야 한다.• Subject 객체의 내부 정보에 변경이 일어났을 때, 해당 항목에 관련된

Observer들에게만 선택적으로 통지한다.

l Encapsulating complex update semantics• 다수의 Subject 객체와 Observer 객체들 간의 관계가 특별히 복잡하고 비효

율적이라면, 변경통보와 변경 값 반영을 전담해주는 ChangeManager 같은별도의 객체를 둘 수 있다.

16

Page 17: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴: 사례 #1

l Sample Codel ClockTimer(ConcreteSubject)

• 시간정보를 가지고 있으며 시간을 보여주는 객체에 시간변경을 알림

l DigitalClock, AnalogClock(ConcreteObserver)• ClockTimer에서 시간정보를 가져와서 화면에 보여주는 역할

Subject Observer

17

Subject

ClockTimer

Observer

DigitalClock AnalogClock

Page 18: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴: 사례 #1

class Subject {public:

virtual ~Subject();virtual void Attach(Observer* o) {

_observers->Append(o);}virtual void Detach(Observer* o) {

_observers->Remove(o);}virtual void Notify() {

ListIterator<Observer*> i(_observers);for (i.First(); !i.IsDone(); i.Next())

i.CurrentItem()->Update(this);}

protected:Subject();

private:List<Observer*> *_observers;

};

class ClockTimer : public Subject {public:

ClockTimer();virtual int GetHour(); // return Hourvirtual int GetMinute(); // return Minutevirtual int GetSecond(); // return Secondvoid Tick() {

// update internal time-keeping state// ...Notify();

}};

Iterator를이용하여등록한모든Observer 객체들에게변화를알림

18

class Subject {public:

virtual ~Subject();virtual void Attach(Observer* o) {

_observers->Append(o);}virtual void Detach(Observer* o) {

_observers->Remove(o);}virtual void Notify() {

ListIterator<Observer*> i(_observers);for (i.First(); !i.IsDone(); i.Next())

i.CurrentItem()->Update(this);}

protected:Subject();

private:List<Observer*> *_observers;

};

class ClockTimer : public Subject {public:

ClockTimer();virtual int GetHour(); // return Hourvirtual int GetMinute(); // return Minutevirtual int GetSecond(); // return Secondvoid Tick() {

// update internal time-keeping state// ...Notify();

}};

상태변화발생Notify() 함수호출

Page 19: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴: 사례 #1

class DigitalClock: public Widget, public Observer {public:

DigitalClock(ClockTimer* s) {_subject = s; _subject->Attach(this);

}virtual ~DigitalClock() {

_subject->Detach(this);}

virtual void Update(Subject* theChangedSubject) {if (theChangedSubject == _subject)

Draw();}virtual void Draw() {

// get the new values from the subjectint hour = _subject->GetHour();int minute = _subject->GetMinute();// etc.// draw the digital clock

}private:

ClockTimer* _subject;};

class AnalogClock : public Widget, public Observer {public:

AnalogClock(ClockTimer*);virtual void Update(Subject*);virtual void Draw();// ...

};필요정보를가지고있는객체가변경을통보하였으면 다시그림

19

class DigitalClock: public Widget, public Observer {public:

DigitalClock(ClockTimer* s) {_subject = s; _subject->Attach(this);

}virtual ~DigitalClock() {

_subject->Detach(this);}

virtual void Update(Subject* theChangedSubject) {if (theChangedSubject == _subject)

Draw();}virtual void Draw() {

// get the new values from the subjectint hour = _subject->GetHour();int minute = _subject->GetMinute();// etc.// draw the digital clock

}private:

ClockTimer* _subject;};

// Client CodeClockTimer* timer = new ClockTimer;AnalogClock* analogClock = new AnalogClock(timer);DigitalClock* digitalClock = new DigitalClock(timer);

timer->tick(); // updates analogClock & digitalClock.

필요정보를가지고있는객체가변경을통보하였으면 다시그림

Page 20: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴: 사례 #1

l 적용사례l Smalltalk Model/View/Controller(MVC)l ET++, THINK libraryl InterViews, Andrew Toolkit, Unidraw: user interface part

l 관련 패턴l Mediator: Observer pattern에서 변경통보와 변경 값 반영을 전담해주는

ChangeManager 같은 별도의 객체를 두는 경우, 이 객체는 Subject 객체와Observer 객체들 사이의 상호작용을 조절하는 Mediator 역할을 수행한다.

l Singleton: ChangeManager 같은 경우 일반적으로 하나의 객체만 생성하기 때문에 Singleton pattern을 사용할 수 있다.

l 적용사례l Smalltalk Model/View/Controller(MVC)l ET++, THINK libraryl InterViews, Andrew Toolkit, Unidraw: user interface part

l 관련 패턴l Mediator: Observer pattern에서 변경통보와 변경 값 반영을 전담해주는

ChangeManager 같은 별도의 객체를 두는 경우, 이 객체는 Subject 객체와Observer 객체들 사이의 상호작용을 조절하는 Mediator 역할을 수행한다.

l Singleton: ChangeManager 같은 경우 일반적으로 하나의 객체만 생성하기 때문에 Singleton pattern을 사용할 수 있다.

20

Page 21: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

옵서버 패턴: 사례 #2(Mutual Fund)Note: HiGrowthMutualFund starts with 3 shares of Awesome, assumes price of 1.0, and has non-Awesome holdings totalling 400.0Note: MedGrowthMutualFund starts with 2 shares of Awesome, assumes price of 1.0, and has non-Awesome holdings totalling 300.0Note: LoGrowthMutualFund starts with 1 shares of Awesome, assumes price of 1.0, and has non-Awesome holdings totalling 200.0

Enter 'quit': Any other input to continue.go onEnter the current price of Awesome Inc. in decimal form.32.1Value of Lo Growth Mutual Fund changed from 201.0 to 232.1Value of Med Growth Mutual Fund changed from 302.0 to 364.2Value of Hi Growth Mutual Fund changed from 403.0 to 496.3

Enter 'quit': Any other input to continue.go onEnter the current price of Awesome Inc. in decimal form.21.0Value of Lo Growth Mutual Fund changed from 232.1 to 221.0Value of Med Growth Mutual Fund changed from 364.2 to 342.0Value of Hi Growth Mutual Fund changed from 496.3 to 463.0

Enter 'quit': Any other input to continue.

21

Note: HiGrowthMutualFund starts with 3 shares of Awesome, assumes price of 1.0, and has non-Awesome holdings totalling 400.0Note: MedGrowthMutualFund starts with 2 shares of Awesome, assumes price of 1.0, and has non-Awesome holdings totalling 300.0Note: LoGrowthMutualFund starts with 1 shares of Awesome, assumes price of 1.0, and has non-Awesome holdings totalling 200.0

Enter 'quit': Any other input to continue.go onEnter the current price of Awesome Inc. in decimal form.32.1Value of Lo Growth Mutual Fund changed from 201.0 to 232.1Value of Med Growth Mutual Fund changed from 302.0 to 364.2Value of Hi Growth Mutual Fund changed from 403.0 to 496.3

Enter 'quit': Any other input to continue.go onEnter the current price of Awesome Inc. in decimal form.21.0Value of Lo Growth Mutual Fund changed from 232.1 to 221.0Value of Med Growth Mutual Fund changed from 364.2 to 342.0Value of Hi Growth Mutual Fund changed from 496.3 to 463.0

Enter 'quit': Any other input to continue.

Page 22: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

Observer Example: Mutual Funds

ObservablenotifyObservers()

Observerupdate( Observable, Object )

MutualFundvalue

numAwesomeShares

Setup

22

AwesomeIncprice

LongTermMutualFund….

update(…)

Key:Developer Class

Java API Class

MediumTermMutualFund….

update(…)HiGrowthMutualFund….

update(…)

Client

Page 23: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

Pattern #17 – 상태 패턴

l 패턴 요약l 상태 객체를 따로 만들어 포함하게 하고 상태 객체에게 위임하여 동작하

게 함

객체의 상태에 의하여 결정된 방법으로 객체를

동작하게 할 때 사용

l 패턴 요약l 상태 객체를 따로 만들어 포함하게 하고 상태 객체에게 위임하여 동작하

게 함

23

Page 24: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

상태 패턴 - 동기

당신은 새로운 프로젝트의 프로그램 reviewer 책임을 맡았다.Reviewer로 당신은 팀원들이 개발한 핵심 코드를 살펴보고,논리상의 문제점이나 좋지 않은 설계구조를 지적해 주어야 한다.오늘 살펴본 코드에는, 특정 객체가 자신의 상태에 따라 다른행동을 하기 위하여 if 문장을 많이 사용하였다. 그러다 보니,함수의 크기가 커지고 객체상태가 많은 경우 해당 객체의 구현이더욱복잡해졌다. 개발자에게조언해줄해결방법은?

당신은 새로운 프로젝트의 프로그램 reviewer 책임을 맡았다.Reviewer로 당신은 팀원들이 개발한 핵심 코드를 살펴보고,논리상의 문제점이나 좋지 않은 설계구조를 지적해 주어야 한다.오늘 살펴본 코드에는, 특정 객체가 자신의 상태에 따라 다른행동을 하기 위하여 if 문장을 많이 사용하였다. 그러다 보니,함수의 크기가 커지고 객체상태가 많은 경우 해당 객체의 구현이더욱복잡해졌다. 개발자에게조언해줄해결방법은?

24

당신은 새로운 프로젝트의 프로그램 reviewer 책임을 맡았다.Reviewer로 당신은 팀원들이 개발한 핵심 코드를 살펴보고,논리상의 문제점이나 좋지 않은 설계구조를 지적해 주어야 한다.오늘 살펴본 코드에는, 특정 객체가 자신의 상태에 따라 다른행동을 하기 위하여 if 문장을 많이 사용하였다. 그러다 보니,함수의 크기가 커지고 객체상태가 많은 경우 해당 객체의 구현이더욱복잡해졌다. 개발자에게조언해줄해결방법은?

함수내에서단순상태변수값으로행동을나누어실행하는코드를어떻게개선할수있을까?

함수내에서단순상태변수값으로행동을나누어실행하는코드를어떻게개선할수있을까?

Page 25: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

상태 패턴 - 동기

[해결방안]l 객체의 가능한 상태 개수 만큼 State class를 작성한다.

• 예) Socket 연결을 대표하는 TCPConnection class가 가질 수 있는 상태를Established(연결), Listen(대기), Closed(끊김) 라고 가정하면 각각 TCPEstablished, TCPListen, TCPClosed class를 만든다.

l 일반적으로 State class의 interface는 특정 상태에 따라 객체의 행위가 달라지는함수들을 포함한다.

TCPState

TCPEstablished

TCPListen

TCPClosed

[해결방안]l 객체의 가능한 상태 개수 만큼 State class를 작성한다.

• 예) Socket 연결을 대표하는 TCPConnection class가 가질 수 있는 상태를Established(연결), Listen(대기), Closed(끊김) 라고 가정하면 각각 TCPEstablished, TCPListen, TCPClosed class를 만든다.

l 일반적으로 State class의 interface는 특정 상태에 따라 객체의 행위가 달라지는함수들을 포함한다.

25

TCPListen

TCPConnectionActiveOpen()PassiveOpen()Close()Transmit()GetOption()

TCPStateActiveOpen()PassiveOpen()Close()Transmit()

상태에따라다르게동작하는함수들

Page 26: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

상태 패턴 - 동기

l TCPConnection class와 State class에 자신의 상태를 변화시킬 수 있는ChangeState() 함수를 추가한다.

l State 객체가 TCPConnection 객체를 알 수 있도록 한다.• 함수를 호출할 때 인자로 TCPConnection 객체를 넘겨주던가, 아니면 각 State 객체가

생성될 때 TCPConnection 객체 reference를 가지든가. à 여기서는 전자로

TCPConnectionActiveOpen()PassiveOpen()Close()Transmit()GetOption()ChangeState()

TCPStateActiveOpen()PassiveOpen()Close()Transmit()ChangeState()

l TCPConnection class와 State class에 자신의 상태를 변화시킬 수 있는ChangeState() 함수를 추가한다.

l State 객체가 TCPConnection 객체를 알 수 있도록 한다.• 함수를 호출할 때 인자로 TCPConnection 객체를 넘겨주던가, 아니면 각 State 객체가

생성될 때 TCPConnection 객체 reference를 가지든가. à 여기서는 전자로

26

TCPStateActiveOpen(TCPConnection *)PassiveOpen(TCPConnection *)Close(TCPConnection *)Transmit(TCPConnection *, TCPStream *)ChangeState(TCPConnection *, TCPState *)

Page 27: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

상태 패턴 - 동기

l 상태변수 대신 초기 State 객체를 가진다.

l 상태변수 값에 따라 분기되는 각 행위들을 제각기 분리하여 위에서 만든 각 State class에 집어넣는다.

class TCPConnection {…TCPState *_state;

};

TCPConnection::TCPConnection() {_state = new TCPClosed(); // 초기상태

}

l 상태변수 대신 초기 State 객체를 가진다.

l 상태변수 값에 따라 분기되는 각 행위들을 제각기 분리하여 위에서 만든 각 State class에 집어넣는다.

27

TCPConnection::Transmit() {if (state==CLOSED) {

……

} else if (state==ESTABLISHED) {……

} else if ( state== LISTEN) {…

} }

TCPClosed::Transmit(TCPConnection *t) {…

}

TCPEstablished::Transmit(TCPConnection *t) {…

}

TCPListen::Transmit(TCPConnection *t) {…

}

Page 28: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

상태 패턴 - 동기

l 기존 객체의 상태에 의존적인 함수는 State 객체로의 delegation으로 구현한다.

TCPConnection::Transmit() {if (state==CLOSED) {

……

} else if (state==ESTABLISHED) {……

} else if ( state== LISTEN) {…

} }

TCPConnection::Transmit() {_state->Transmit();

}

TCPConnection객체가가지고있는 State객체

l 기존 객체의 상태에 의존적인 함수는 State 객체로의 delegation으로 구현한다.

28

TCPConnection::Transmit() {if (state==CLOSED) {

……

} else if (state==ESTABLISHED) {……

} else if ( state== LISTEN) {…

} }

TCPConnection객체가가지고있는 State객체

Page 29: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

상태 패턴 - 동기

l TCPConnection 객체의 상태변화는 내부 함수나 State 객체에서만 일으킬 수 있다(ChangeState() 를 private으로).

l TCPConnection 객체 상태 변화 예

aTCPStateaTCPConnectionaClientChangeState()

29

void TCPConnection::ChangeState(TCPState *s) {delete _state;_state = s;

}void TCPState::ChangeState(TCPConnection *t, TCPState *s) {

t->ChangeState(t, s);}void TCPClosed::ActiveOpen(TCPConnection *t) {

// do connection operation.ChangeState(t, new TCPEstablished );

}

Page 30: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

상태 패턴 - 동기

l State 객체가 독자적인 정보를 가지지 않는다면, 객체를 여러 개 가질 필요는 없음.• State 객체는 특정 객체의 행위들을 각 상태에 따라 모아 놓은 것이기 때문에 단순 함수

집합으로 간주해도 됨• Singleton pattern 활용• 앞의 예에서 Singleton pattern을 사용한 모습

void TCPConnection::ChangeState(TCPState *s) {_state = s;

}void TCPState::ChangeState(TCPConnection *t, TCPState *s) {

t->ChangeState(t, s);}void TCPClosed::ActiveOpen(TCPConnection *t) {

// do connection operation.ChangeState(t, TCPEstablished::Instance() );

}

30

void TCPConnection::ChangeState(TCPState *s) {_state = s;

}void TCPState::ChangeState(TCPConnection *t, TCPState *s) {

t->ChangeState(t, s);}void TCPClosed::ActiveOpen(TCPConnection *t) {

// do connection operation.ChangeState(t, TCPEstablished::Instance() );

}

Page 31: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

상태 패턴 - 동기

l Class diagram

31

Page 32: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

상태 패턴

l 의도l 객체의 내부 상태가 변경되었을 때 그에 따라 객체의 행위도 변경되게 한

다. (마치 다른 class 의 객체가 된 것 처럼)

l 별칭l Objects for States

l 적용 범위l 객체의 행위가 해당 객체의 상태에 따라 달라질 때.l 객체의 함수 코드가 객체의 상태에 따라 큰 부분의 조건문장으로 구성되

어 있을 때(if 문장, switch 문장)

l 의도l 객체의 내부 상태가 변경되었을 때 그에 따라 객체의 행위도 변경되게 한

다. (마치 다른 class 의 객체가 된 것 처럼)

l 별칭l Objects for States

l 적용 범위l 객체의 행위가 해당 객체의 상태에 따라 달라질 때.l 객체의 함수 코드가 객체의 상태에 따라 큰 부분의 조건문장으로 구성되

어 있을 때(if 문장, switch 문장)

32

Page 33: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

상태 패턴

l Structure

33

Page 34: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

상태 패턴

l 참여요소l Context(TCPConnection)

• 현재 상태를 나타내는 ConcreteState 객체 reference를 가진다.

l State(TCPState)• Context 객체의 현재 상태에 따라 다른 행위를 하는 함수들의 interface 를 정의한다.

l ConcreteState(TCPEstablished, TCPClosed, TCPListen)• 각 Class들은 Context 객체의 특정 상태에 따라 수행되는 행위들을 구현

l 협동l Context 객체는 상태 의존적인 요청에 대해서는 ConcreteState 객체에 요청을 delegation한

다.l Context 객체가 ConcreteState 객체 함수를 호출할 때 자신의 reference를 인자로 넘길 수

있다.l 일반적으로 Client가 Context 객체를 초기화하는 것 외에는 상태변환에 직접적인 개입을 하

지 않는다.l Context 객체의 상태변화는 Context 나 ConcreteState 객체의 작업 수행도중에 일어난다.

l 참여요소l Context(TCPConnection)

• 현재 상태를 나타내는 ConcreteState 객체 reference를 가진다.

l State(TCPState)• Context 객체의 현재 상태에 따라 다른 행위를 하는 함수들의 interface 를 정의한다.

l ConcreteState(TCPEstablished, TCPClosed, TCPListen)• 각 Class들은 Context 객체의 특정 상태에 따라 수행되는 행위들을 구현

l 협동l Context 객체는 상태 의존적인 요청에 대해서는 ConcreteState 객체에 요청을 delegation한

다.l Context 객체가 ConcreteState 객체 함수를 호출할 때 자신의 reference를 인자로 넘길 수

있다.l 일반적으로 Client가 Context 객체를 초기화하는 것 외에는 상태변환에 직접적인 개입을 하

지 않는다.l Context 객체의 상태변화는 Context 나 ConcreteState 객체의 작업 수행도중에 일어난다.

34

Page 35: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

상태 패턴

l 결과l It localizes state-specific behavior and partitions behavior for different state

• State pattern은 특정 상태에 연관된 행위들을 하나의 객체로 만든다. • 모든 상태의존 코드가 State subclass로 존재하기 때문에 새로운 상태를 추가하여 구현

하기가 용이하다.• 상태조건에 따라 다중의 If 문장으로 구성된 복잡한 함수를 simple하게 만든다.

l It makes state transitions explicit• 상태 전환이 일어나면 참조하는 객체가 바뀐다.

l State objects can be shared• State subclass들이 개별적 내부 정보를 가지지 않는 다면 그 객체들은 공유될 수 있다.

즉, 하나의 객체가 여러 Context에서 사용가능하다.

l 결과l It localizes state-specific behavior and partitions behavior for different state

• State pattern은 특정 상태에 연관된 행위들을 하나의 객체로 만든다. • 모든 상태의존 코드가 State subclass로 존재하기 때문에 새로운 상태를 추가하여 구현

하기가 용이하다.• 상태조건에 따라 다중의 If 문장으로 구성된 복잡한 함수를 simple하게 만든다.

l It makes state transitions explicit• 상태 전환이 일어나면 참조하는 객체가 바뀐다.

l State objects can be shared• State subclass들이 개별적 내부 정보를 가지지 않는 다면 그 객체들은 공유될 수 있다.

즉, 하나의 객체가 여러 Context에서 사용가능하다.

35

Page 36: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

상태 패턴

l 구현l Who defines the state transitions?

• 상태 전환에 대한 고정된 규칙은 없다.• Context나 ConcreteState 객체의 특정 함수 내에서 필요에 따라

Context::ChangeState() 함수를 호출하여 상태 전환할 수 있다.

l A table-based alternative• 상태전환 표: 각 상태에서 가능한 입력에 따라 전환되는 상태를 기록한 표• 표를 검색해야 하므로 속도가 느림• 사람이 이해하기 어려움• 상태 전환 도중에 특정한 행동을 수행하게 만드는 것이 어려움

l Creating and destroying State objects• 각 State 객체를 필요할 때 생성하고, 필요 없을 때 삭제한다.• 개별 내부정보가 없을 경우에는 Singleton pattern을 이용하여 하나의 객체만 생성하여

사용한다.

l 구현l Who defines the state transitions?

• 상태 전환에 대한 고정된 규칙은 없다.• Context나 ConcreteState 객체의 특정 함수 내에서 필요에 따라

Context::ChangeState() 함수를 호출하여 상태 전환할 수 있다.

l A table-based alternative• 상태전환 표: 각 상태에서 가능한 입력에 따라 전환되는 상태를 기록한 표• 표를 검색해야 하므로 속도가 느림• 사람이 이해하기 어려움• 상태 전환 도중에 특정한 행동을 수행하게 만드는 것이 어려움

l Creating and destroying State objects• 각 State 객체를 필요할 때 생성하고, 필요 없을 때 삭제한다.• 개별 내부정보가 없을 경우에는 Singleton pattern을 이용하여 하나의 객체만 생성하여

사용한다.

36

Page 37: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

상태 패턴 – 사례 #1

l Sample Codel Motivation 해결방안에 대한 프로그램 코드l Classes

• TCPConnection, TCPState, TCPEstablished, TCPClosed, TCPListen

class TCPConnection {public:

TCPConnection();void ActiveOpen();void PassiveOpen();void Close();void Send();void Transmit(TCPStream *s);void ProcessStream(TCPStream *s);

private:friend class TCPState;void ChangeState(TCPState*);

private:TCPState* _state;

};

TCPConnection::TCPConnection () {_state = TCPClosed::Instance();

}void TCPConnection::ChangeState (TCPState* s) {

_state = s;}void TCPConnection::ActiveOpen () {

_state->ActiveOpen(this);}void TCPConnection::PassiveOpen () {

_state->PassiveOpen(this);}void TCPConnection::Close () {

_state->Close(this);}void TCPConnection::Send() {

_state->Send(this); }void TCPConnection::Transmit(TCPStream *s) {

_state->Transmit(this, s); }

37

class TCPConnection {public:

TCPConnection();void ActiveOpen();void PassiveOpen();void Close();void Send();void Transmit(TCPStream *s);void ProcessStream(TCPStream *s);

private:friend class TCPState;void ChangeState(TCPState*);

private:TCPState* _state;

};

TCPConnection::TCPConnection () {_state = TCPClosed::Instance();

}void TCPConnection::ChangeState (TCPState* s) {

_state = s;}void TCPConnection::ActiveOpen () {

_state->ActiveOpen(this);}void TCPConnection::PassiveOpen () {

_state->PassiveOpen(this);}void TCPConnection::Close () {

_state->Close(this);}void TCPConnection::Send() {

_state->Send(this); }void TCPConnection::Transmit(TCPStream *s) {

_state->Transmit(this, s); }

state 객체로요청 delegation

Page 38: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

상태 패턴: 사례 #1

class TCPState {public:

virtual void ActiveOpen(TCPConnection*) {}virtual void PassiveOpen(TCPConnection*) {}virtual void Close(TCPConnection*) {}virtual void Send(TCPConnection *) {}virtual void Transmit(TCPConnection*, TCPStream*) {}

protected:void ChangeState(TCPConnection* t, TCPState* s) {

t->ChangeState(s);}

};

•상태에따라서로다르게행동하는함수들• Empty body function으로default 함수구현

Established 상태에서만Transmit() 함수가정보를전송

38

class TCPState {public:

virtual void ActiveOpen(TCPConnection*) {}virtual void PassiveOpen(TCPConnection*) {}virtual void Close(TCPConnection*) {}virtual void Send(TCPConnection *) {}virtual void Transmit(TCPConnection*, TCPStream*) {}

protected:void ChangeState(TCPConnection* t, TCPState* s) {

t->ChangeState(s);}

}; class TCPEstablished : public TCPState {public:

static TCPState* Instance();

virtual void Transmit(TCPConnection* t, TCPStream* o) {t->ProcessStream(o);

}virtual void Close(TCPConnection* t) {

// send FIN, receive ACK of FINChangeState(t, TCPListen::Instance());

}private:

TCPEstablished() { … }};

Established 상태에서Close()가호출되면대기상태(Listen)로변환

Page 39: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

상태 패턴

class TCPClosed : public TCPState {public:

static TCPState* Instance();

void ActiveOpen (TCPConnection* t) {// send SYN, receive SYN, ACK, etc.ChangeState(t, TCPEstablished::Instance());

}void PassiveOpen (TCPConnection* t) {

ChangeState(t, TCPListen::Instance());}// …

private:TCPClosed() { … }// ...

};

Close 상태에서 ActiveOpen() 호출하면 Established 상태로전환

class TCPListen : public TCPState {public:

static TCPState* Instance();

void TCPListen::Send (TCPConnection* t) {// send SYN, receive SYN, ACK, etc.ChangeState(t, TCPEstablished::Instance());

}// …

private:TCPListen() { … }// …

}39

class TCPClosed : public TCPState {public:

static TCPState* Instance();

void ActiveOpen (TCPConnection* t) {// send SYN, receive SYN, ACK, etc.ChangeState(t, TCPEstablished::Instance());

}void PassiveOpen (TCPConnection* t) {

ChangeState(t, TCPListen::Instance());}// …

private:TCPClosed() { … }// ...

};

class TCPListen : public TCPState {public:

static TCPState* Instance();

void TCPListen::Send (TCPConnection* t) {// send SYN, receive SYN, ACK, etc.ChangeState(t, TCPEstablished::Instance());

}// …

private:TCPListen() { … }// …

}

Listen 상태에서 Send() 호출하면Established 상태로전환

Singleton pattern 사용

Page 40: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

상태 패턴

l 적용 사례l TCP Connection Protocol (Johnson and Zweig)l HotDraw, Unidraw: drawing editor frameworksl Coplien’s Envelope-Letter idiom

l 관련 패턴l Singletons: State 객체를 하나만 생성해야 될 때 Singleton pattern 사용l Flyweight: 여러 종류의 State 객체들을 공유해야 할 때 Flyweight pattern을 활

용할 수 있다.

40

Page 41: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

Pattern #18 – 커멘드 패턴

l 패턴 요약l 오퍼레이션을 클래스로 정의

서비스를 호출할 때 융통성을 높이려고 사용

(예, undo 오퍼레이션)

l 패턴 요약l 오퍼레이션을 클래스로 정의

41

Page 42: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴 - 동기

PDA’s GUI System 개발 프로젝트에 참여한 당신이 맡은 업무는window main-menu 부분의 설계이다. 각 application은 main-menu를 가지고 있고, main-menu의 각 menu 들은 여러 개의menu-item을 가지고 있다. 사용자가 특정 menu-item을선택하면해당 menu-item에 연동된기능이수행된다.당신은어떤식으로설계할것인가?

PDA’s GUI System 개발 프로젝트에 참여한 당신이 맡은 업무는window main-menu 부분의 설계이다. 각 application은 main-menu를 가지고 있고, main-menu의 각 menu 들은 여러 개의menu-item을 가지고 있다. 사용자가 특정 menu-item을선택하면해당 menu-item에 연동된기능이수행된다.당신은어떤식으로설계할것인가?

main-menu

42

main-menu

‘File’ menu‘Open’ menu:문서열기기능수행

Page 43: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴 - 동기

l Application’s menu 모델링

지정된기능수행

43

다양한기능요청방법을지원하기위해서는각요청을하는객체(menuitem, toolbarButton, hotkey)와요청자체를분리하는것이필요

다양한기능요청방법을지원하기위해서는각요청을하는객체(menuitem, toolbarButton, hotkey)와요청자체를분리하는것이필요

•파일열기기능호출- ‘File’ – ‘Open’ menu-item 선택- Toolbar에서 file open icon 선택- Hotkey(Ctrl-O) 누르기

Page 44: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴 - 동기

l Application’s menu 모델링 -2l 기능요청(예: ‘문서열기’) 자체를 객체화 – Commandl 기능요청을 원하는 각 객체에 해당 Command 객체를 연결

예) ‘File’-‘Open’ menu-item, Toolbar’s open icon, Ctrl-O hotkeyl 기능요청을 원하는 각 객체가 선택될 때 연결된 Command 객체 실행 –

command.Execute();

44

지정된 command 객체실행

Page 45: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴 - 동기

[Command class hierarchy](1) PasteCommand: 현 위치에 Clipboard 내용 붙여 넣기

; 다른 객체(document)에 요청 보내기(2) OpenCommand: 문서열기

; 몇 개의 연산 조합으로 기능 수행.

(1)

45

(2) (1)

Page 46: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴 - 동기

l [Command class hierarchy -2]

(3) MacroCommand: 다른 Command 객체들을연속으로실행

46

Page 47: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴 - 동기

[Undo Mechanism: Commands’ undo()]-실행된작업되돌리기-각 Command 객체마다자신의작업을되돌릴수있는 Undo() 함수구현-지금까지실행된 Command 객체들을모아두고, 이를역순으로 Undo() 호출

47

Page 48: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴

l 의도l Encapsulate a request as an objectl 기능요청을 객체화함으로써, 동적으로 기능설정을 바꾸거나 실행된 기능들을 기

록하거나 실행된 작업들을 재복구 시킬 수 있다.

l 별칭l Action, Transaction

48

Page 49: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴

l 적용범위

l MenuItem 객체의 경우처럼, 객체에 수행되어야 할 행위(action)를 동적으로 설정할 때

l 작업 수행을 요청한 시점과 실제 작업이 수행되어야 할 시점을 다르게 할 필요가있을 때

l Undo 기능을 지원하고자 할 때l System 의 기능수행 정도를 기록하고 싶을 때

; 각 Command 객체들이 수행될 때 마다 자신의 기록을 남김l 기본적인 행위들을 조합하여 더욱 복잡한 행위를 실행하고자 할 때

; MacroCommand 사용

l 적용범위

l MenuItem 객체의 경우처럼, 객체에 수행되어야 할 행위(action)를 동적으로 설정할 때

l 작업 수행을 요청한 시점과 실제 작업이 수행되어야 할 시점을 다르게 할 필요가있을 때

l Undo 기능을 지원하고자 할 때l System 의 기능수행 정도를 기록하고 싶을 때

; 각 Command 객체들이 수행될 때 마다 자신의 기록을 남김l 기본적인 행위들을 조합하여 더욱 복잡한 행위를 실행하고자 할 때

; MacroCommand 사용

49

Page 50: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴

l Structure

50

Page 51: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴

l Participantsl Command

; 연산 수행에 대한 Interface 정의 - Execute()

l ConcreteCommand (OpenCommand, PasteCommand, …); 연산 수행을 위한 Execute() 함수 구현; Execute() 함수는 적절한 Receiver의 함수(들)을 호출해서 기능 수행

l Client (Application); ConcreteCommand 객체를 생성하고, 해당 객체에 Receiver 객체를 설정한다.

l Invoker (MenuItem); Command 객체에게 기능수행을 요청한다.

l Receiver (Document, Application); ConcreteCommand 객체들이 연산을 수행하는데 필요한 기능들을 제공한다.

l Participantsl Command

; 연산 수행에 대한 Interface 정의 - Execute()

l ConcreteCommand (OpenCommand, PasteCommand, …); 연산 수행을 위한 Execute() 함수 구현; Execute() 함수는 적절한 Receiver의 함수(들)을 호출해서 기능 수행

l Client (Application); ConcreteCommand 객체를 생성하고, 해당 객체에 Receiver 객체를 설정한다.

l Invoker (MenuItem); Command 객체에게 기능수행을 요청한다.

l Receiver (Document, Application); ConcreteCommand 객체들이 연산을 수행하는데 필요한 기능들을 제공한다.

51

Page 52: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴

l Collaborationl Steps

1. Client 가 ConcreteCommand 객체를 생성하고, 해당 객체에 Receiver 객체를 설정한다.

2. Invoker 객체는 적합한 ConcreteCommand 객체의 reference를 가진다.3. Invoker 객체는 자신이 가지고 있는 ConcreteCommand객체의 reference를 통하여

기능을 요청한다. - command->Execute()4. 요청을 받은 ConcreteCommand 객체는 Step1. 에서 설정된 Receiver 객체의 함수

를 이용하여 요청을 실행한다.

52

Page 53: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴

1

2

53

2

34

Page 54: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴

l 결과l 작업 수행을 요청하는 객체와 실제 작업을 수행하는 객체를 분리시킨다.l 작업 요청 자체가 객체가 되기 때문에, 다른 객체처럼 ‘작업요청’ 자체를 저장하

고, 복구하고, 확장할 수 있다.l 기본적인 행위들을 조합하여 더욱 복잡한 행위를 실행하고자 할 때l 기존 코드의 변경 없이 새로운 Command 를 추가할 수 있다.

54

Page 55: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴

l 구현l How intelligent should a command be?

• Command는 ‘단순히 받은 request를 Receiver 객체에게 전달만 하는것’ 에서부터 ‘주된Receiver 객체 도움 없이 자신이 모든 것을 구현하는 것’ 까지 그 범위가 다양하다.

l Supporting undo and redo?• Command 로 실행된 작업들을 복구하려면 어떻게? • 실행된 Command 객체들을 저장한 History List 필요• Motivation -6. Slide 참조.

l Using C++ template• Execute() 함수에 인자가 필요 없고, undo 기능이 필요 없다면, ConcreteCommand

class 를 쉽게 만들기 위하여 C++ template을 이용할 수 있다.

l 구현l How intelligent should a command be?

• Command는 ‘단순히 받은 request를 Receiver 객체에게 전달만 하는것’ 에서부터 ‘주된Receiver 객체 도움 없이 자신이 모든 것을 구현하는 것’ 까지 그 범위가 다양하다.

l Supporting undo and redo?• Command 로 실행된 작업들을 복구하려면 어떻게? • 실행된 Command 객체들을 저장한 History List 필요• Motivation -6. Slide 참조.

l Using C++ template• Execute() 함수에 인자가 필요 없고, undo 기능이 필요 없다면, ConcreteCommand

class 를 쉽게 만들기 위하여 C++ template을 이용할 수 있다.

55

Page 56: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴 – 사례 #1

• C++ template 코드 예

template <class Receiver>class SimpleCommand : public Command {public:

typedef void (Receiver::* Action)();

SimpleCommand(Receiver* r, Action a) :_receiver(r), _action(a) { }

virtual void Execute() {(_receiver->*_action)();

}private:

Action _action;Receiver* _receiver;

};

Receiver class를인자로

56

template <class Receiver>class SimpleCommand : public Command {public:

typedef void (Receiver::* Action)();

SimpleCommand(Receiver* r, Action a) :_receiver(r), _action(a) { }

virtual void Execute() {(_receiver->*_action)();

}private:

Action _action;Receiver* _receiver;

};

class MyClass {public:void Action();

};

// Client CodeMyClass* receiver = new MyClass;// ...Command* aCommand =

new SimpleCommand<MyClass>(receiver, &MyClass::Action);// ...aCommand->Execute();

Command 객체에Receiver객체와함수지정

Page 57: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴 – 사례 #1

l Sample Codel Motivation -4, -5. Slide에 나오는 Class diagram 구현

class Document {public:

Document(const char*);void Open();void Paste();

};

class Application {public:Application();void Add(Document*);

};

class Command {public:

virtual ~Command();

virtual void Execute() = 0;protected:

Command();};

class OpenCommand : public Command {public:

OpenCommand(Application* a) {_application = a;

}virtual void Execute() {

const char* name = AskUser();

if (name != 0) {Document* document = new Document(name);_application->Add(document);document->Open();

}}

protected:virtual const char* AskUser();

private:Application* _application;char* _response;

};

Receiver 객체인application 지정

57

class Document {public:

Document(const char*);void Open();void Paste();

};

class Application {public:Application();void Add(Document*);

};

class Command {public:

virtual ~Command();

virtual void Execute() = 0;protected:

Command();};

class OpenCommand : public Command {public:

OpenCommand(Application* a) {_application = a;

}virtual void Execute() {

const char* name = AskUser();

if (name != 0) {Document* document = new Document(name);_application->Add(document);document->Open();

}}

protected:virtual const char* AskUser();

private:Application* _application;char* _response;

};

application 과document 객체를이용하여요청구현

Page 58: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴 – 사례 #1

class PasteCommand : public Command {public:

PasteCommand(Document* doc) {_document = doc;

}virtual void Execute() {

_document->Paste();}

private:Document* _document;

};

class MacroCommand : public Command {public:

MacroCommand();virtual ~MacroCommand();

virtual void Add(Command* c) {_cmds->Append(c);

}virtual void Remove(Command* c) {

_cmds->Remove(c);}virtual void Execute() {

ListIterator<Command*> i(_cmds);for (i.First(); !i.IsDone(); i.Next()) {

Command* c = i.CurrentItem();c->Execute();

}}

private:List<Command*>* _cmds;

};

수행될 Command 객체들추가및삭제

58

class MacroCommand : public Command {public:

MacroCommand();virtual ~MacroCommand();

virtual void Add(Command* c) {_cmds->Append(c);

}virtual void Remove(Command* c) {

_cmds->Remove(c);}virtual void Execute() {

ListIterator<Command*> i(_cmds);for (i.First(); !i.IsDone(); i.Next()) {

Command* c = i.CurrentItem();c->Execute();

}}

private:List<Command*>* _cmds;

};

Iterator 을이용하여저장되어있는 Command 객체들의 Execute() 호출

List template을이용하여Command 객체들을저장

Page 59: 객체지향설계와패턴 Lecture #13: 행위패턴(2)•각Class들은Context 객체의특정상태에따라수행되는행위들을구현 l협동 lContext 객체는상태의존적인요청에대해서는ConcreteState

커멘드 패턴 – 사례 #1

l 사용 사례l MacApp system, THINK class library : Undoable operationl ET++, InterViews, Unidraw system

l 관련 패턴l MacroCommand 를 구현하는데 Composite pattern을 사용할 수 있다.l Undo 기능을 위해서 보관해야 될 관련 객체들의 상태정보를 표현하기 위하여

Memento pattern을 적용할 수 있다.l Undo 기능을 위하여 Command 객체가 History list에 복사될 때 Prototype

pattern을 적용할 수 있다.

l 사용 사례l MacApp system, THINK class library : Undoable operationl ET++, InterViews, Unidraw system

l 관련 패턴l MacroCommand 를 구현하는데 Composite pattern을 사용할 수 있다.l Undo 기능을 위해서 보관해야 될 관련 객체들의 상태정보를 표현하기 위하여

Memento pattern을 적용할 수 있다.l Undo 기능을 위하여 Command 객체가 History list에 복사될 때 Prototype

pattern을 적용할 수 있다.

59