20 行为型模式-----观察者模式

模式动机(Observer Pattern)将数据的存储与显示进行分离设计,能够很好地降低模块直接的耦合性。但是我们在后台更新数据时总希望前台的显示也做出相应的变化,观察者模式很好地解决了这个问题。

观察者模式定义了对象之间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动更新状态,即对于一份后台数据,可以存在多个显示器负责显示并同时接收后台数据变更的通知。

观察者模式包含如下参与者:

Subject:

1> 可以有任意多个观察者同时观察同一目标

2> 可以添加观察者、删除观察者

Observer:

1>  为那些在目标发生改变时需要得到通知的对象定义一个更新接口

ConcreteSubject:

1> 将当前状态subjectState存到具体观察者ConcreteObserver中

2>  当状态发生改变时,及时通知各个观察者更新状态

ConcreteObserver:

1> 维护一个指向ConcreteSubject对象的指针subject

2> 存储有关状态observerState,该状态应该与具体目标的状态subjectState保持一致

 

当ConcreteSubject中的状态发生改变时,其会通知ConcreteObserver更新状态以保持状态的一致性。一个目标可以存在任意个观察者对象,一旦目标的状态发生改变,所有的观察者都会接到通知,但是目标对象可以不关心到底谁是它的观察者,其只需要调用Notify()就可以了。

 

模式结构图:

 

模式代码:

bt_观察者模式.h:

 1 #ifndef OP_H
 2 #define OP_H
 3 #include <iostream>
 4 #include <list>
 5 using namespace std;
 6 
 7 /*
 8     抽象观察者:
 9     1> 为那些在目标发生改变时需要得到通知的对象定义一个更新接口
10 */
11 class Subject;
12 class Observer
13 {
14 public:
15     virtual ~Observer(){ }
16     virtual void Update() = 0;
17 };
18 
19 /*
20     抽象目标:
21     1> 可以有任意多个观察者同时观察同一目标
22     2> 可以添加观察者、删除观察者
23 */
24 class Subject
25 {
26 public:
27     Subject(){ observers = new list<Observer*>; }
28     virtual ~Subject(){ delete observers; }
29     void Attach(Observer* obv)
30     {
31         cout << "添加具体观察者" << endl;
32         observers->insert(observers->end(), obv);
33     }
34     void Detach(Observer* obv)
35     {
36         cout << "删除具体观察者" << endl;
37         delete obv;
38         observers->remove(obv);
39     }
40     void Notify()
41     {
42         cout << "通知具体观察者更新状态->" << endl;
43         list<Observer*>::iterator iter;
44         for(iter = observers->begin(); iter != observers->end(); iter++)
45         {
46             (*iter)->Update();
47         }
48     }
49 
50 private:
51     list<Observer*>* observers;
52 };
53 
54 /*
55     具体目标:
56     1> 将当前状态subjectState存到具体观察者ConcreteObserver中
57     2> 当状态发生改变时,及时通知各个观察者更新状态
58 */
59 class ConcreteSubject : public Subject
60 {
61 public:
62     int GetState(){ return subjectState; }
63     void SetState(int s)
64     {
65         subjectState = s;
66         Notify();      // 通知所有观察者更新状态
67     }
68 
69 private:
70     int subjectState;
71 };
72 /*
73     具体观察者:
74     1> 维护一个指向ConcreteSubject对象的指针subject
75     2> 存储有关状态observerState,该状态应该与具体目标的状态subjectState保持一致
76 */
77 class ConcreteObserver : public Observer
78 {
79 public:
80     ConcreteObserver(ConcreteSubject* cs, int state) : subject(cs), observerState(state){}
81     virtual void Update()
82     {
83         cout << "->具体观察者更新状态" << endl;
84         cout << "更新前状态为:" << observerState << endl;
85         observerState = subject->GetState();
86         cout << "更新后状态为:" << observerState << endl;
87     }
88 
89 private:
90     ConcreteSubject* subject;
91     int observerState;
92 };
93 
94 #endif // OP_H

测试用例.cpp:

 1 #include "bt_观察者模式.h"
 2 
 3 int main()
 4 {
 5 
 6     cout << "***** 观察者模式测试 *****" << endl;
 7     ConcreteSubject* cs = new ConcreteSubject;
 8     Observer* observer1 = new ConcreteObserver(cs, 6666);
 9     Observer* observer2 = new ConcreteObserver(cs, 7777);
10     cs->Attach(observer1);  // 注册观察者
11     cs->Attach(observer2);    // 注册观察者
12     cs->SetState(8888);
13 
14                 // cs->Notify();     // 由客户调用Notify
15 
16     delete observer2;
17     delete observer1;
18     delete cs;
19 
20     return 0;
21 }

模式分析:

:: 观察者模式将众多观察者和其依赖的具体目标进行解耦,使得每个目标仅知道存在观察者,但是不知道具体观察者是什么类型的。

:: 目标发送通知时使用广播方式,凡是被登记过的观察者都会接收到并及时更新状态。

:: Notify()函数由谁来调用呢?

如果是由具体目标对象调用Notify(),那么必须每改变一次状态,就调用一次Notify()。但是,如果让客户负责调用Notify(),虽然可以对于多次改变只调用一次Notify(),但是可能容易忘记调用,导致丢失状态。上例中就是由具体目标负责调用Notify的例子,如下所示为由客户调用Notify()的例子:

ConcreteSubject::SetState(int s)中去掉Notify():

void SetState(int s)

{

    subjectState = s;

}

主程序中增加cs->Notify()语句即可,结果和上述完全相同。

:: 当然也可以扩展目标的注册接口,使得不同类型的观察者只对特定类型的事件感兴趣,这样可以提高观察者更新状态的效率。当一种事件发生,目标仅通知那些注册为对该类事件感兴趣的观察者。

:: 如果依赖关系比较复杂,比如一个观察者依赖多个具体目标,而每个具体目标又对应多个观察者,这种多对多的依赖关系可以由一个专门的中介者来处理。一般而言,这种类型的中介者只应该存在唯一实例,因此最好用单例来设计它。

 

 

 

原文地址:https://www.cnblogs.com/benxintuzi/p/4575245.html