zl程序教程

您现在的位置是:首页 >  后端

当前栏目

观察者模式

模式 观察者
2023-09-14 09:12:20 时间

【1】什么是观察者模式?

观察者模式,定义一种一对多的依赖关系,多个观察者对象同时监听某一个主题对象。

当这个主题对象状态上发生变化时,会通知所有观察者对象,他们能够自动更新自己,随主题对象状态改变做出对应的行为表现。

【2】观察者模式代码示例:

代码示例如下:

  1 #include <iostream>
  2 #include <string>
  3 #include <list>
  4 using namespace std;
  5 
  6 class Observer;
  7 
  8 // 管理观察者的基类
  9 class Subject
 10 {
 11 public:
 12     string action;   // 主题名称
 13 protected:
 14     list<Observer*> observers;  // 观察者的容器
 15 
 16 public:
 17     virtual void attach(Observer*) = 0;
 18     virtual void detach(Observer*) = 0;
 19     virtual void notify() = 0;
 20 };
 21 
 22 // 观察者基类
 23 class Observer
 24 {
 25 protected:
 26     string name;
 27     Subject *sub;
 28 
 29 public:
 30     Observer(string name, Subject *sub)
 31     {
 32         this->name = name;
 33         this->sub = sub;
 34     }
 35     string getName()
 36     {
 37         return name;
 38     }
 39 
 40     virtual void update() = 0;
 41 };
 42 
 43 // 炒股票(观察者其一)
 44 class StockObserver : public Observer
 45 {
 46 public:
 47     StockObserver(string name, Subject *sub) : Observer(name, sub)
 48     {}
 49 
 50     void update();
 51 };
 52 
 53 void StockObserver::update()
 54 {
 55     cout << name << " 收到消息:" << sub->action << endl;
 56     if (sub->action == "梁所长来了!")
 57     {
 58         cout << "我马上关闭股票,装做很认真工作的样子!" << endl;
 59     }
 60 }
 61 
 62 // 看NBA比赛(观察者其一)
 63 class NBAObserver : public Observer
 64 {
 65 public:
 66     NBAObserver(string name, Subject *sub) : Observer(name, sub)
 67     {}
 68     void update();
 69 };
 70 
 71 void NBAObserver::update()
 72 {
 73     cout << name << " 收到消息:" << sub->action << endl;
 74     if (sub->action == "梁所长来了!")
 75     {
 76         cout << "我马上关闭NBA,装做很认真工作的样子!" << endl;
 77     }
 78 }
 79 
 80 // 玩游戏(观察者其一)
 81 class GameObserver : public Observer
 82 {
 83 public:
 84     GameObserver(string name, Subject *sub) : Observer(name, sub)
 85     {}
 86 
 87     void update();
 88 };
 89 
 90 void GameObserver::update()
 91 {
 92     cout << name << " 收到消息:" << sub->action << endl;
 93     if (sub->action == "梁所长来了!")
 94     {
 95         cout << "我马上退出游戏,装做很认真工作的样子!" << endl;
 96     }
 97 }
 98 
 99 // 管理观察者的实现类(作为被观察者)
100 class Secretary : public Subject
101 {
102 public:
103     void attach(Observer *observer)
104     {
105         cout << "add: " << observer->getName() << endl;
106         observers.push_back(observer);
107     }
108 
109     void detach(Observer *observer)
110     {
111         list<Observer *>::iterator iter = observers.begin();
112         while (iter != observers.end())
113         {
114             if ((*iter) == observer)
115             {
116                 cout << "erase: " << observer->getName() << endl;
117                 observers.erase(iter++);
118             }
119             else
120             {
121                 ++iter;
122             }
123         }
124     }
125 
126     void notify()
127     {
128         list<Observer *>::iterator iter = observers.begin();
129         while (iter != observers.end())
130         {
131             (*iter)->update();
132             ++iter;
133         }
134     }
135 };
136 
137 
138 void main()
139 {
140     Subject *pDwq = new Secretary();  // 主题对象,作为被观察者
141 
142     Observer *pXs = new NBAObserver("xiaoshuai", pDwq);  // 小帅,作为观察者(监听者)
143     Observer *pZy = new GameObserver("zhuoyue", pDwq);  // 卓越,作为观察者(监听者)
144     Observer *pLm = new StockObserver("liming", pDwq); // 李明,作为观察者(监听者)
145 
146     // 绑定观察者与被观察者
147     cout << "登记监听者: " << endl;
148     pDwq->attach(pXs);
149     pDwq->attach(pZy);
150     pDwq->attach(pLm);
151 
152     // 测试广播动作
153     cout << endl << "测试广播动作效果: " << endl;
154     cout << "发出动作1效果:去吃饭了!" << endl;
155     pDwq->action = "去吃饭了!";
156     pDwq->notify();
157 
158     cout << endl << "发出动作2效果:梁所长来了!" << endl;
159     pDwq->action = "梁所长来了!";
160     pDwq->notify();
161 
162     // 解除绑定监听
163     cout << endl << "解除监听者: " << endl;
164     pDwq->detach(pLm);
165     pDwq->detach(pZy);
166     pDwq->detach(pXs);
167 
168     delete pDwq;
169     delete pXs;
170     delete pZy;
171     delete pLm;
172 
173     system("pause");
174 }
175 
176 // run out:
177 /*
178 登记监听者:
179 add: xiaoshuai
180 add: zhuoyue
181 add: liming
182 
183 测试广播动作效果:
184 发出动作1效果:去吃饭了!
185 xiaoshuai 收到消息:去吃饭了!
186 zhuoyue 收到消息:去吃饭了!
187 liming 收到消息:去吃饭了!
188 
189 发出动作2效果:梁所长来了!
190 xiaoshuai 收到消息:梁所长来了!
191 我马上关闭NBA,装做很认真工作的样子!
192 zhuoyue 收到消息:梁所长来了!
193 我马上退出游戏,装做很认真工作的样子!
194 liming 收到消息:梁所长来了!
195 我马上关闭股票,装做很认真工作的样子!
196 
197 解除监听者:
198 erase: liming
199 erase: zhuoyue
200 erase: xiaoshuai
201 请按任意键继续. . .

 【3】观察者模式的优缺点

观察者模式的效果有以下的优点:

第一、观察者模式在被观察者和观察者之间建立一个抽象的耦合。

  被观察者角色所知道的只是一个具体观察者列表,每一个具体观察者都符合一个抽象观察者的接口。

  被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。

  由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。如果被观察者和观察者都被扔到一起,那么这个对象必然跨越抽象化和具体化层次。

第二、观察者模式支持广播通讯。被观察者会向所有的登记过的观察者发出通知。

观察者模式有下面的缺点:

第一、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。

第二、如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察者模式是要特别注意这一点。

第三、如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。

第四、虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。

 

Good  Good  Study, Day  Day  Up.

顺序   选择   循环   总结