2020년 7월 8일 수요일

GOF Design Pattern - Observer






설명

 
객체간의 일관성을 유지하도록 관련된 객체를 같이 업데이트 하도록 하는 방법.


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 의 관계를 레지스터에 저장하고, 호출하는 작업도 구현되어 있음.


댓글 없음:

댓글 쓰기

List