010 --- 第14章 观察者模式
简述:
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够主动更新自己。
观察者模式包括:抽象主题类、具体主题类、抽象观察者类、具体观察者类。
抽象主题类:它把所有对观察者对象的指针保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
具体主题类:具体主题,将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有登记过的观察者发出通知。
抽象观察者类:抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。
具体观察者类:具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。
应用场景:需要一个标志相应所有状态的改变,主题类封装了观察者列表,主题类改变状态通知观察者,所有观察者改变自身的状态
注:开发环境调整为VS2017,操作系统win11
观察者模式代码:C++与C#的区别要注意相互包含的问题,同时要注意声明顺序。
1 #include <iostream> 2 #include <list> 3 #include <string> 4 using namespace std; 5 6 // 抽象观察者类 7 class CObserver 8 { 9 public: 10 virtual void UpDate() {} 11 }; 12 13 // 抽象通知者类 14 class CSubject 15 { 16 private: 17 list<CObserver*> m_listObserver; 18 19 public: 20 virtual void Attach(CObserver* pObserver) 21 { 22 m_listObserver.push_back(pObserver); 23 } 24 25 virtual void Detach(CObserver* pObserver) 26 { 27 m_listObserver.remove(pObserver); 28 } 29 30 virtual void Notify() 31 { 32 for (CObserver* pObserver : m_listObserver) 33 pObserver->UpDate(); 34 } 35 }; 36 37 // 具体通知者类 38 class CConcreteSubject : public CSubject 39 { 40 private: 41 string m_szSubjectState; 42 43 public: 44 void SetSubjectState(string szSubjectState) 45 { 46 m_szSubjectState = szSubjectState; 47 } 48 49 string GetSubjectState() 50 { 51 return m_szSubjectState; 52 } 53 }; 54 55 // 具体观察者类 56 class CConcreteObserver : public CObserver 57 { 58 private: 59 string m_szName; 60 CConcreteSubject* m_pSubject; 61 62 public: 63 CConcreteObserver(CConcreteSubject* pSubject, string szName) 64 { 65 m_szName = szName; 66 m_pSubject = pSubject; 67 } 68 69 virtual void UpDate() 70 { 71 cout << "观察者[" << m_szName << "]的新状态是[" 72 << m_pSubject->GetSubjectState() << "]" << endl; 73 } 74 75 void SetSubject(CConcreteSubject* pSubject) 76 { 77 m_pSubject = pSubject; 78 } 79 80 CSubject* GetSubject() 81 { 82 return m_pSubject; 83 } 84 }; 85 86 int main() 87 { 88 CConcreteSubject ConcreteSubject; 89 CConcreteObserver ConcreteObserver1(&ConcreteSubject, "X"); 90 CConcreteObserver ConcreteObserver2(&ConcreteSubject, "Y"); 91 CConcreteObserver ConcreteObserver3(&ConcreteSubject, "Z"); 92 93 ConcreteSubject.Attach(&ConcreteObserver1); 94 ConcreteSubject.Attach(&ConcreteObserver2); 95 ConcreteSubject.Attach(&ConcreteObserver3); 96 97 ConcreteSubject.Detach(&ConcreteObserver2); 98 99 ConcreteSubject.SetSubjectState("ABC"); 100 101 ConcreteSubject.Notify(); 102 103 system("pause"); 104 return 0; 105 }
输出结果:
注:C++是没有C#中的委托事件这种语法的,但是可以用函数指针来实现,笔者比较懒,没写。
例:前台监测老板是否回来了。
代码如下:
1 #include <iostream> 2 #include <list> 3 #include <string> 4 using namespace std; 5 6 //class CSecretary; 7 class CSubject; 8 // 抽象观察者类 9 class CObserver 10 { 11 protected: 12 string m_szName; 13 //CSecretary* m_pSecretary; 14 CSubject* m_pSubject; 15 16 public: 17 //CObserver(string szName, CSecretary* pSecretary); 18 CObserver(string szName, CSubject* pSubject) : m_szName(szName), m_pSubject(pSubject) {}; 19 virtual ~CObserver() {}; 20 virtual void UpDate() {}; 21 }; 22 23 //// 秘书类(双向耦合代码) 24 //class CSecretary 25 //{ 26 //private: 27 // list<CObserver*> m_listCObserver; 28 // string m_szAction; 29 // 30 //public: 31 // CSecretary() {} 32 // 33 // virtual ~CSecretary() 34 // { 35 // if (!m_listCObserver.empty()) 36 // { 37 // m_listCObserver.clear(); 38 // } 39 // } 40 // 41 // virtual void Attach(CObserver* pObserver) 42 // { 43 // m_listCObserver.push_back(pObserver); 44 // } 45 // 46 // virtual void Detach(CObserver* pDelObserver) 47 // { 48 // if (!m_listCObserver.empty()) 49 // { 50 // m_listCObserver.remove(pDelObserver); 51 // } 52 // } 53 // 54 // virtual void Notify() 55 // { 56 // for (CObserver* pObserver : m_listCObserver) 57 // { 58 // pObserver->UpDate(); 59 // } 60 // } 61 // 62 // void SetSecretaryAction(string szAction) 63 // { 64 // m_szAction = szAction; 65 // } 66 // 67 // string GetSecretaryAction() 68 // { 69 // return m_szAction; 70 // } 71 //}; 72 73 // 抽象主题类 74 class CSubject 75 { 76 private: 77 list<CObserver*> m_listCObserver; 78 string m_szAction; 79 80 public: 81 CSubject() {}; 82 virtual ~CSubject() 83 { 84 if (!m_listCObserver.empty()) 85 { 86 m_listCObserver.clear(); 87 } 88 } 89 90 virtual void Attach(CObserver* pObserver) 91 { 92 m_listCObserver.push_back(pObserver); 93 } 94 95 virtual void Detach(CObserver* pDelObserver) 96 { 97 if (!m_listCObserver.empty()) 98 { 99 m_listCObserver.remove(pDelObserver); 100 } 101 } 102 103 virtual void Notify() 104 { 105 for (CObserver* pObserver : m_listCObserver) 106 { 107 pObserver->UpDate(); 108 } 109 } 110 111 void SetSubjectState(string szAction) 112 { 113 m_szAction = szAction; 114 } 115 116 string GetSubjectState() 117 { 118 return m_szAction; 119 } 120 }; 121 122 // 看股票的同事(具体观察者类) 123 class CStockObserver : public CObserver 124 { 125 public: 126 //CStockObserver(string szName, CSecretary* pSecretary) 127 // : CObserver(szName, pSecretary) 128 //{ 129 // 130 //} 131 132 CStockObserver(string szName, CSubject* pSubject) 133 : CObserver(szName, pSubject) {} 134 135 virtual ~CStockObserver() {} 136 137 virtual void UpDate() 138 { 139 //cout << "[" << m_pSecretary->GetSecretaryAction() << "]" 140 // << "[" << m_szName << "]" << "关闭股票行情,继续工作" << endl; 141 142 cout << "[" << m_pSubject->GetSubjectState() << "]" 143 << "[" << m_szName << "]" << "关闭股票行情,继续工作。。。" << endl; 144 } 145 }; 146 147 // 看NBA的同事(具体观察者类) 148 class CNBAObserver : public CObserver 149 { 150 public: 151 //CNBAObserver(string szName, CSecretary* pSecretary) 152 // : CObserver(szName, pSecretary) {} 153 154 CNBAObserver(string szName, CSubject* pSubject) 155 : CObserver(szName, pSubject) {} 156 157 virtual ~CNBAObserver() {} 158 159 virtual void UpDate() 160 { 161 //cout << "[" << m_pSecretary->GetSecretaryAction() << "]" 162 // << "[" << m_szName << "]" << "关闭NBA直播,继续工作" << endl; 163 164 cout << "[" << m_pSubject->GetSubjectState() << "]" 165 << "[" << m_szName << "]" << "关闭NBA直播,继续工作。。。" << endl; 166 } 167 }; 168 169 // 我嫌麻烦,把具体主题类的共有内容放到抽象主题类里写了,懒得写两遍 170 // 老板(具体主题类) 171 class CBoss : public CSubject 172 { 173 }; 174 175 // 秘书(具体主题类) 176 class CReception : public CSubject 177 { 178 }; 179 180 // C++资源回收,记住哪里创建就要哪里释放 181 // 其他作用域只是指针传递,如果在别的地方释放,容易导致多次释放报错 182 int main() 183 { 184 //CSecretary Secretary; 185 CBoss Boss; 186 187 //CStockObserver StockObserver("GHL", &Secretary); 188 //CNBAObserver NBAObserver("GGG", &Secretary); 189 CStockObserver StockObserver("GHL", &Boss); 190 CNBAObserver NBAObserver("GGG", &Boss); 191 192 //Secretary.Attach(&StockObserver); 193 //Secretary.Attach(&NBAObserver); 194 195 Boss.Attach(&StockObserver); 196 Boss.Attach(&NBAObserver); 197 198 //Secretary.SetSecretaryAction("老板回来了!"); 199 Boss.SetSubjectState("我胡汉三回来了!"); 200 201 //Secretary.Notify(); 202 Boss.Notify(); 203 204 205 cout << "\n华丽的分割线\n" << endl; 206 CReception Reception; 207 208 CStockObserver StockObserve1("123", &Reception); 209 CNBAObserver NBAObserve1("456", &Reception); 210 211 Reception.Attach(&StockObserve1); 212 Reception.Attach(&NBAObserve1); 213 Reception.Detach(&NBAObserve1); 214 215 Reception.SetSubjectState("老板回来了!"); 216 217 Reception.Notify(); 218 219 system("pause"); 220 return 0; 221 }
输出结果: