设计模式之观察者模式
观察者模式定义了一种一对多的依赖关系,让多个观察者同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。其UML图如下:
在ConcretSubject内部有一个Observer的列表,当Subject的状态发生改变时,会通知列表内的所有的观察者。而观察者都实现了统一的接口,而不同的观察者在该接口中做出了不同的响应。其示例代码如下:
1 // ObserverModel.h文件
2 #pragma once
3 #include <iostream>
4 #include <vector>
5 #include <string>
6 #include <algorithm>
7 // 观察者
8 class Observer
9 {
10 public:
11 virtual void Update() = 0;
12 };
13
14 class ConcreteObserver_0 : public Observer
15 {
16 public:
17 virtual void Update()
18 {
19 std::cout << "ConcreteObserver_0 知道了" << std::endl;
20 }
21 };
22
23 class ConcreteObserver_1 : public Observer
24 {
25 public:
26 virtual void Update()
27 {
28 std::cout << "ConcreteObserver_1 知道了" << std::endl;
29 }
30 };
31 // 通知者
32 class Subject
33 {
34 public:
35 virtual void Attatch(Observer * p) = 0;
36 virtual void Detach(Observer * p) = 0;
37 virtual void Notify() = 0;
38 virtual void changeState(std::string str)
39 {
40 m_str = str;
41 Notify();
42 }
43
44 protected:
45 std::string m_str;
46 };
47 // 传统观察者模式
48 class ConcreteSubject : public Subject
49 {
50 public:
51 ConcreteSubject()
52 {
53 ;
54 }
55 ~ConcreteSubject()
56 {
57 m_vec.clear();
58 }
59 virtual void Attatch(Observer * p)
60 {
61 m_vec.push_back(p);
62 }
63 virtual void Detach(Observer * p)
64 {
65 auto it = find(m_vec.begin(), m_vec.end(), p);
66 if (m_vec.end() != it)
67 {
68 m_vec.erase(it);
69 }
70 }
71 virtual void Notify()
72 {
73 for (auto it = m_vec.cbegin(); it != m_vec.cend(); it++)
74 {
75 std::cout << m_str << " ";
76 (*it)->Update();
77 }
78 }
79 private:
80 std::vector<Observer * > m_vec;
81 };
测试代码如下:
1 #include <iostream>
2 #include "ObserverModel.h"
3
4 int main()
5 {
6 using namespace std;
7 // 观察者模式
8 ConcreteSubject * p = new ConcreteSubject();
9 Observer * p1 = new ConcreteObserver_0();
10 Observer * p2 = new ConcreteObserver_1();
11 p->Attatch(p1);
12 p->Attatch(p2);
13 p->changeState("老板来啦");
14 delete p;
15 delete p2;
16 delete p1;
17
18 getchar();
19 return 0;
20 }
测试结果如下图:
观察者模式也有不足,观察者模式需要观察者需要实现相同的接口。但是如果已经些好的类或者第三方的类库则就没办法实现该功能了。所以可以稍稍改进一下,就是把Subject类中的关于观察者的列表修改为函数指针的列表。示例码如下:
1 // ObserverModel.h文件
2 #pragma once
3 #include <iostream>
4 #include <vector>
5 #include <string>
6 #include <algorithm>
7 // 函数指针版本
8 class ConcreteObserverFunc_0
9 {
10 public:
11 static void func_0()
12 {
13 std::cout << "ConcreteObserver_0 知道了" << std::endl;
14 }
15 };
16
17 class ConcreteObserverFunc_1
18 {
19 public:
20 static void func_1()
21 {
22 std::cout << "ConcreteObserver_1 知道了" << std::endl;
23 }
24 };
25
26 class SubjectFunc
27 {
28 public:
29 virtual void Attatch(void (*p)()) = 0;
30 virtual void Detach(void(*p)()) = 0;
31 virtual void Notify() = 0;
32 virtual void changeState(std::string str)
33 {
34 m_str = str;
35 Notify();
36 }
37 protected:
38 std::string m_str;
39 };
40
41 class ConcreteSubjectFunc : public SubjectFunc
42 {
43 private:
44 std::vector<void(*)()> m_func;
45 public:
46 ConcreteSubjectFunc()
47 {
48 ;
49 }
50 ~ConcreteSubjectFunc()
51 {
52 m_func.clear();
53 }
54 virtual void Attatch(void (*p)())
55 {
56 m_func.push_back(p);
57 }
58 virtual void Detach(void(*p)())
59 {
60 auto it = find(m_func.begin(), m_func.end(), p);
61 if (m_func.end() != it)
62 {
63 m_func.erase(it);
64 }
65 }
66 virtual void Notify()
67 {
68 for (auto it = m_func.cbegin(); it != m_func.cend(); it++)
69 {
70 std::cout << m_str << " ";
71 (*it)();
72 }
73 }
74 };
测试代码如下:
1 #include <iostream>
2 #include "ObserverModel.h"
3
4 int main()
5 {
6 using namespace std;
7 // 观察者模式
8 ConcreteObserverFunc_0 * p1Func = new ConcreteObserverFunc_0();
9 ConcreteObserverFunc_1 * p2Func = new ConcreteObserverFunc_1();
10 ConcreteSubjectFunc * pFunc = new ConcreteSubjectFunc();
11 pFunc->Attatch(&ConcreteObserverFunc_0::func_0);
12 pFunc->Attatch(&ConcreteObserverFunc_1::func_1);
13 pFunc->changeState("我的天哪");
14 delete p1Func;
15 delete p2Func;
16 delete pFunc;
17
18 getchar();
19 return 0;
20 }
测试结果如下图: