Thinking Different






Observer Pattern - 옵저버 패턴


  • 한 객체의 상태가 바뀌면 그 객체에 이존하는 다른 객체들 모두에게 연락이 가고 자동으로 내용이 갱신되는 패턴
  • 1 : N(다) 의 의존성으로 정의한다
  • 일방적 통지 (Broadcast) 방식의 패턴




샘플 코드)

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//------------------------------------------------------------------
// Observer 인터페이스
class Observer
{
public:
    virtual void update() = 0;
};
 
//------------------------------------------------------------------
// ConcreteObserver 상속 클래스
class ConcreteObserver : public Observer
{
public:
    void update() override { cout << this << " : update" << endl; }
};
 
//------------------------------------------------------------------
// Subject 인터페이스 (옵저버들 관리 및 통지)
class Subject
{
public:
    void attach(Observer* o) { mList.AddTail(o); }
    void detach(Observer* o) { mList.RemoveAt(mList.Find(o)); }
 
protected:
    void notify()
    {
        POSITION pos = mList.GetHeadPosition();
        while (pos != NULL)
            mList.GetNext(pos)->update();
    }
 
public:
    virtual void change() = 0;
 
private:
    CAtlList<Observer*> mList;
};
 
//------------------------------------------------------------------
// ConcreteSubject 상속 클래스
class ConcreteSubject : public Subject
{
public:
    void change() override { notify(); }
};
 
 
//------------------------------------------------------------------
// Main
int _tmain(int argc, _TCHAR* argv[])
{
    Subject* pSubject = new ConcreteSubject;
 
    Observer* pObserver1 = new ConcreteObserver;
    Observer* pObserver2 = new ConcreteObserver;
    Observer* pObserver3 = new ConcreteObserver;
 
    pSubject->attach(pObserver1);
    pSubject->attach(pObserver2);
    pSubject->attach(pObserver3);
 
    pSubject->change();
 
    pSubject->detach(pObserver1);
    pSubject->detach(pObserver2);
    pSubject->detach(pObserver3);
 
    pSubject->change();
 
    delete pSubject;
    delete pObserver1;
    delete pObserver2;
    delete pObserver3;
 
    return 0;
}






예제를 통한 옵저버 패턴(Observer Pattern) 알아보기



예제) 방송사 -> 시청자 관계를 통한 예제



방송사와 옵저버(시청자)와의 관계를 예를 들었습니다. 방송사는 시청자들을 하나의 컨테이너(리스트)에서 관리하고 시청등록자들에게 방송을 송출하는 부분을 맡고 있고, 옵저버 - 시청자쪽에서는 방송사에서 오는 방송을 그대로 방송시청하도록 1 : N 의 관계로 옵저버 패턴을 설계하였습니다.



예제 코드)

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <atlcoll.h>
 
#if _UNICODE
typedef wstring tstring;
#else
typedef string tstring;
#endif
 
//------------------------------------------------------------------
// Observer 인터페이스
class 옵저버_인터페이스
{
public:
    virtual void 방송시청(const TCHAR* news) = 0;
    virtual const TCHAR* 이름() const = 0;
};
 
//------------------------------------------------------------------
// ConcreteObserver 상속 클래스
class 시청자 : public 옵저버_인터페이스
{
public:
    시청자(const TCHAR* name) : mName(name) {}
 
public:
    void 방송시청(const TCHAR* news) override { cout << mName << " : " << news << endl; }
    const TCHAR* 이름() const { return mName.c_str(); }
 
private:
    tstring mName;
};
 
//------------------------------------------------------------------
// Subject 인터페이스 (옵저버들 관리 및 통지)
class 방송사_인터페이스
{
public:
    void 방송시청등록(옵저버_인터페이스* o) { mList.AddTail(o); cout << "방송 신청 : " << o->이름() << endl; }
    void 방송시청해제(옵저버_인터페이스* o) { mList.RemoveAt(mList.Find(o));  cout << "방송 해지 : " << o->이름() << endl; }
 
protected:
    void 송출(const TCHAR* news)
    {
        POSITION pos = mList.GetHeadPosition();
        while (pos != NULL)
            mList.GetNext(pos)->방송시청(news);
    }
 
public:
    virtual void 뉴스(const TCHAR* news) = 0;
 
private:
    CAtlList<옵저버_인터페이스*> mList;
};
 
//------------------------------------------------------------------
// ConcreteSubject 상속 클래스
class 코리아방송 : public 방송사_인터페이스
{
public:
    void 뉴스(const TCHAR* news) override { 송출(news); }
};
 
 
//------------------------------------------------------------------
// Main
int _tmain(int argc, _TCHAR* argv[])
{
    방송사_인터페이스* pSubject = new 코리아방송;
 
    옵저버_인터페이스* pObserver1 = new 시청자("홍길동");
    옵저버_인터페이스* pObserver2 = new 시청자("태평양");
    옵저버_인터페이스* pObserver3 = new 시청자("비둘기");
 
    pSubject->방송시청등록(pObserver1);
    pSubject->방송시청등록(pObserver2);
    pSubject->방송시청등록(pObserver3);
 
    pSubject->뉴스("날씨를 말씀드리겠습니다.");
 
    pSubject->방송시청해제(pObserver1);
    pSubject->방송시청해제(pObserver2);
    
    pSubject->뉴스("뉴스 속보입니다.");
 
    delete pSubject;
    delete pObserver1;
    delete pObserver2;
    delete pObserver3;
 
    return 0;
}


예제 결과)