[디자인 패턴] 관찰자 패턴 - Observer
해당 패턴에 들어가기에 앞서 관찰자 디자인 패턴은 닷넷에 (무려! MSDN!!)에 설명되어 있고 또한
사용 가능한 인터페이스를 제공해주고 있습니다. [MSDN 관찰자 패턴] <-- 링크
관찰자 패턴은 쉽게 엑셀에서 어떤 수치(주체 subject)를 여러 그래프 (감시자 observer)를 두어
수치가 변동 될 때 그래프가 자동을 갱신된다거나, 퀘스트 내용이 변동 될때 등의 일 대 다의 사이에서 주체가 변동 된다면 감시자에게 전달되는 패턴을 말합니다.
목적
객체 사이에 일 대 다의 의존 관계를 정의해 두어, 어떤 객체의 상태가 변할 때 그 객체에 의존성을 가진 다른 객체들이 그 변화를 통지 받고 자동으로 갱신 될 수 있게 만듭니다.
활용
- 한 객체에 가해진 변경으로 다른 객체를 변경해야 할 때.
- 한 객체가 다른 객체에 갱신 된 내용을 전달 할 때 객체들이 갱신 된 객체를 몰라도 될 때
장점
- 일관성을 유지하면서도 객체간의 결합성을 높이지 않습니다.
- 상호작용(게시 - 구독)관계로, 변경된 정보를 통보하는데 용이합니다.
- 결합이 추상적이며, 최소화 되어있습니다.
단점
- 전달된 정보가 올바른 정보인지 올바르지 못한 정보 인지를 판단하는 처리가 필요합니다.
- 브로드 캐스트 방식으로 전달 받은 감시자에게 불필요한 정보가 있을 때의 처리를 해주어야 합니다.
구현
먼저 관찰자(감시자) 클래스를 추상 클래스로 정의합니다.
1 2 3 4 5 6 7 8 9 10 11 | class Observer { public : virtual ~Observer(); virtual void Update(Subject* theChangedSubject) = 0; protected: Observer(); }; | cs |
주체 클래스를 정희합니다.
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 | class Subject { public : virtual ~Subject(); virtual void Attach(Observer*); virtual void Detach(Observer*); virtual void Notify(); protected : Subject(); private : list<Observer*> *_observers; }; void Subject::Attach(Observer* ob) { _observers->push_back(ob); } void Subject::Detach(Observer* ob) { _observers->remove(ob); } void Subject::Notify() { auto iter_observer = _observers->begin(); for (iter_observer; iter_observer != _observers->end ; iter_observer.operator++) { (*iter_observer)->Update(this); } } | cs |
주체 클래스를 상속받은 감시될 객체를 정의합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class ClockTimer : public Subject { public: ClockTimer(); virtual int GetHour(); virtual int GetMinute(); virtual int GetSecond(); void Tick(); }; void ClockTimer::Tick() { // change Timer Notify(); } | cs |
관찰자 클래스를 상속받은 객체를 정의합니다.
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 | class DigitalClock : public Widget, public Observer { public : DigitalClock(ClockTimer*); virtual ~DigitalClock(); virtual void Update(Subject*) override; virtual void Draw(); private : ClockTimer* _subject; }; DigitalClock::DigitalClock(ClockTimer* subject) { _subject = subject; _subject->Attach(this); } DigitalClock::~DigitalClock() { _subject->Detach(this); } void DigitalClock::Update(Subject* changeSubject) { if (changeSubject == _subject) { Draw(); } } void DigitalClock::Draw() { int hour = _subject->GetHour(); int minute = _subject->GetMinute(); // show Timer } | cs |
만약 필요하다면 다른 감시자 (예제에서는 아날로그 시계)또한 정의합니다.
1 2 3 | ClockTimer* timer = new ClockTimer(); DigitalClock* digitalClock = new DigitalClock(timer); AnalogClock* analogClock = new AnalogClock(timer) | cs |
복잡한 갱신의 의미 구조를 캡슐화함으로써, ChangeManager (주체 클래스) 객체는 주체와 감시자 사이의 중재자 역할을 합니다. 객체는 단일체 패턴을 써서 시스템에 하나만 존재하고 전역적으로 접근이 가능하도록 만들 수 있습니다.
'프로그래밍 관련 > 디자인 패턴' 카테고리의 다른 글
[행동 패턴] 반복자 패턴 - Iterator (0) | 2017.01.05 |
---|---|
[행동 패턴] 명령 패턴 - Command (0) | 2016.09.20 |
[생성 패턴] 추상 팩토리 패턴 - Abstract Factory (0) | 2016.07.28 |
디자인 패턴을 공부해보자! (0) | 2016.07.28 |