Observer模式应该可以说是应用最多、影响最广的模式之一,因为Observer的一个实例Model/View/Control(MVC)结构在系统开发架构设计中有着很重要的地位和意义,MVC实现了业务逻辑和表现层的解耦。Observer模式要解决的问题为:建立一个一(Subject)对多(Observer)的依赖关系,并且做到当“一”变化的时候,依赖这个“一”的多也能够同步改变。
在GOF的《设计模式:可复用面向对象软件的基础》一书中对观察者模式是这样说的:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。当一个对象发生了变化,关注它的对象就会得到通知;这种交互也称为发布-订阅(publish-subscribe)。目标是通知的发布者,它发出通知时并不需要知道谁是它的观察者。
最常见的一个例子:对同一组数据进行统计分析时,我们希望能够提供多种形式的表示(例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。这些表示都依赖于同一组数据,我们需要当数据改变的时候,所有的统计显示都能够同时改变。Observer模式就是解决这一问题。
UML类图
Subject(目标)
——目标知道它的观察者。可以有任意多个观察者观察同一个目标;
——提供注册和删除观察者对象的接口。
Observer(观察者)
——为那些在目标发生改变时需获得通知的对象定义一个更新接口。
ConcreteSubject(具体目标)
——将有关状态存入各ConcreteObserver对象;
——当它的状态发生改变时,向它的各个观察者发出通知。
ConcreteObserver(具体观察者)
——维护一个指向ConcreteSubject对象的引用;
——存储有关状态,这些状态应与目标的状态保持一致;
——实现Observer的更新接口以使自身状态与目标的状态保持一致。
观察者模式按照以下方式进行协作:
1、当ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者;
2、在得到一个具体目标的改变通知后,ConcreteObserver对象可向目标对象查询信息。ConcreteObserver使用这些信息以使它的状态与目标对象的状态一致。
适用场合
在以下任一情况下都可以使用观察者模式:
1、当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立的改变和复用;
2、当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变;
3、当一个对象必须通知其它对象,而它又不能假定其它对象是谁;也就是说,你不希望这些对象是紧密耦合的。
代码实现
Observer.h
1 /** 2 * File name: Observer.h 3 * Date: 2017.10.11 4 * Description: Define the observer 5 */ 6 #pragma once 7 #include <iostream> 8 #include <set> 9 #include <string> 10 using namespace std; 11 //抽象主题角色Subject 12 class CObservable; 13 //抽象观察者角色 14 class CObserver 15 { 16 public: 17 CObserver() {}; 18 virtual ~CObserver() {}; 19 //当被观察者的目标发生变化时,通知调用该方法 20 //来自被观察者pObs,扩展参数为pArg 21 virtual void Update(CObservable* pObs, void* pArg = NULL) = 0; 22 }; 23 24 //被观察者,即Subject 25 class CObservable 26 { 27 public: 28 CObservable() : m_bChanged(false) {}; 29 virtual ~CObservable() {}; 30 void Attach(CObserver* pObs); //注册观察者 31 void Detach(CObserver* pObs); //注销观察者 32 void DetachAll(); //注销所有观察者 33 void Notify(void* pArg = NULL); //若状态变化,则遍历观察者,逐个通知更新 34 bool HasChanged(); //测试目标状态是否变化 35 int GetObserversCount(); //获取观察者数量 36 protected: 37 void SetChanged(); //设置状态变化!!!必须继承CObservable才能设置目标状态 38 void ClearChanged(); //初始化目标为未变化状态 39 private: 40 bool m_bChanged; 41 set<CObserver*> m_setObs; 42 }; 43 44 void CObservable::Attach(CObserver* pObs) 45 { 46 if (!pObs) 47 return; 48 m_setObs.insert(pObs); 49 } 50 51 void CObservable::Detach(CObserver* pObs) 52 { 53 if (!pObs) 54 return; 55 m_setObs.erase(pObs); 56 } 57 58 void CObservable::DetachAll() 59 { 60 m_setObs.clear(); 61 } 62 63 void CObservable::SetChanged() 64 { 65 m_bChanged = true; 66 } 67 68 void CObservable::ClearChanged() 69 { 70 m_bChanged = false; 71 } 72 73 bool CObservable::HasChanged() 74 { 75 return m_bChanged; 76 } 77 78 int CObservable::GetObserversCount() 79 { 80 return m_setObs.size(); 81 } 82 83 void CObservable::Notify(void* pArg) 84 { 85 if (!HasChanged()) 86 return; 87 cout << "notify observers..." << endl; 88 ClearChanged(); 89 set<CObserver*>::iterator itr = m_setObs.begin(); 90 for (; itr != m_setObs.end(); itr++) 91 { 92 (*itr)->Update(this, pArg); 93 } 94 } 95 96 //具体主题角色 97 //bloger是发布者,即被观察者(subject) 98 class CBloger : public CObservable 99 { 100 public: 101 void Publish(const string &strContent) 102 { 103 cout << "bloger publish, content: " << strContent << endl; 104 SetChanged(); 105 Notify(const_cast<char*>(strContent.c_str())); 106 } 107 }; 108 109 //portal是发布者,即被观察者(subject) 110 class CPortal : public CObservable 111 { 112 public: 113 void Publish(const string &strContent) 114 { 115 cout << "portal publish, content: " << strContent << endl; 116 SetChanged(); 117 Notify(const_cast<char*>(strContent.c_str())); 118 } 119 }; 120 121 //RSS阅读者,观察者 122 class CRssReader : public CObserver 123 { 124 public: 125 CRssReader(const string &strName) : m_strName(strName) {} 126 virtual void Update(CObservable* pObs, void* pArg = NULL) 127 { 128 char* pContent = static_cast<char*>(pArg); 129 //观察多个目标 130 if (dynamic_cast<CBloger*>(pObs)) 131 { 132 cout << m_strName << " updated from bloger, content: " << pContent << endl; 133 } 134 else if (dynamic_cast<CPortal*>(pObs)) 135 { 136 cout << m_strName << " updated from portal, content: " << pContent << endl; 137 } 138 } 139 private: 140 string m_strName; 141 }; 142 143 //Mail阅读者,观察者 144 class CMailReader : public CObserver 145 { 146 public: 147 CMailReader(const string &strName) : m_strName(strName) {} 148 virtual void Update(CObservable* pObs, void* pArg = NULL) 149 { 150 char* pContent = static_cast<char*>(pArg); 151 if (dynamic_cast<CBloger*>(pObs)) 152 { 153 cout << m_strName << " updated from bloger, content: " << pContent << endl; 154 } 155 else if (dynamic_cast<CPortal*>(pObs)) 156 { 157 cout << m_strName << " updated from portal, content: " << pContent << endl; 158 } 159 } 160 private: 161 string m_strName; 162 };
main.cpp
1 /** 2 * File name: main.cpp 3 * Date: 2017.10.11 4 * Description: An example of using observer 5 */ 6 #include "Observer.h" 7 int main() 8 { 9 //目标(被观察者) 10 CBloger* pBloger = new CBloger(); 11 CPortal* pPortal = new CPortal(); 12 13 //观察者 一个观察者可以观察多个目标 14 CRssReader* pRssReader = new CRssReader("rss reader"); 15 CMailReader* pMailReader = new CMailReader("mail reader"); 16 pBloger->Attach(pRssReader); //bloger注册观察者 17 pBloger->Attach(pMailReader); //bloger注册观察者 18 pPortal->Attach(pRssReader); //portal注册观察者 19 pPortal->Attach(pMailReader); //portal注册观察者 20 //博客发布消息 21 pBloger->Publish("blog shares pattren of design"); 22 cout << endl; 23 24 //门户发布消息 25 pPortal->Publish("portal shares pattern of design"); 26 cout << " portal detached mail reader" << endl; 27 28 pPortal->Detach(pMailReader); 29 30 cout << "portal observers count:" << pPortal->GetObserversCount() << endl << endl; 31 pPortal->Publish("portal shares pattern of design"); 32 33 system("pause"); 34 return 0; 35 }
vs2017运行结果
转自: