설명
객체간의 일관성을 유지하도록 관련된 객체를 같이 업데이트 하도록 하는 방법.
Observer 는 주체가 업데이트 될 때 같이 호환될 객체들의 인터페이스임.
Subject 는 Observer 의 인터페이스를 가지고 그들을 자신의 구독 리스트에 넣고 빼며
Subject 의 수정 시 구독중인 Observer 들의 메소드들을 부를 수 있음.
문제는 Subject 의 변경 사항이 뭔지 Observer 들은 몰라서, 일관성을 위한 작업이 불필요하게 커질 수도 있다는 것.
변경 사항 관련 프로토콜이 추가되면 해결 가능함.
Notify 의 호출은 사용자의 임의의 호출 일수도 있고 Subject 일수도 있는데, 후자는 불필요한 계산이 커진다는 거고, 전자는 사용자가 호출하는걸 까먹을 일이 많다는 거임.
예제 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class Subject { public: virtual ~Subject() = default; virtual void Attach(Observer* o) { _observers.push_back(o); } virtual void Detach(Observer* o) { _observers.remove(o); } virtual void Notify() { for (auto var : _observers) var->Update(this); } protected: Subject() = default; private: std::list<Observer*> _observers; }; | cs |
1 2 3 4 5 6 7 8 | class Observer { public: virtual ~Observer() = default; virtual void Update(Subject* theChangeSubject) = 0; protected: Observer() = default; }; | cs |
1 2 3 4 5 6 7 8 9 10 | class ClockTimer : public Subject { public: ClockTimer() = default; virtual int GetHour() {}; virtual int GetMinute() {}; void Tick() { 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 | class DigitalClock : public Observer { public: DigitalClock(ClockTimer* s) { _subject = s; _subject->Attach(this); } virtual ~DigitalClock() { _subject->Detach(this); } virtual void Update(Subject* s) { if (s == _subject) Draw(); } virtual void Draw() { int hour = _subject->GetHour(); int minute = _subject->GetMinute(); } private: ClockTimer* _subject; }; | cs |
Observer 와 Object 가 구현되어이 있고, 각각 ClockTimer, DigitalClock 을 상속한다.
DigitalClock 이 생성될 때 Observer 인 ClockTimer 를 구독한다.
ClockTimer 는 주기적으로 Notify 를 할 것이고,
여기서 DigitalClock 은 업데이트 할 것이다.
추가 설명
Notify 관련 작업이 복잡하면 하나의 ChangeManager 객체를 만들 수도 있음.
ChangeManager 는 Subject 와 Object 의 관계를 레지스터에 저장하고, 호출하는 작업도 구현되어 있음.
댓글 없음:
댓글 쓰기