窥探观察者模式
观察者模式(obsever pattern)又名发行/订阅模式(publish-subscribe pattern),是事件驱动模型的简化版本,也是我们熟知的MVC架构的核心部分。
下面以博客园订阅博客为例,窥探一下观察者模式蕴含的奥秘:
当博主发表新文章的时候,即博主状态发生了改变,那些订阅的读者就会收到通知,然后进行相应的动作,比如去看文章,或者收藏起来。博主与读者之间存在种一对多的依赖关系。
【对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新】这就是观察者模式,所谓的观察者可以理解为关注博客的读者,被观察的对象(Subject)即为博主,博主自身状态发生改变时会发出通知(Notify),读者(Obsever)可以通过更新操作(Update)获得博主的最新消息。
观察者模式的实现有以下4类角色:
- 抽象主题(Subject):可以用博客的抽象基类来理解,一般用一个抽象类或者一个接口实现。Subject提供依赖于它的观察者 Observer 的注册( Attach) 和注销( Detach)操作,并且提供了使得依赖于它的所有观察者同步的操作( Notify)。
- 抽象观察者(Observer):可以用观察者的抽象基类来理解,抽象观察者一般用一个抽象类或者一个接口实现。在这个示意性的实现中,更新接口只包含一个方法(即Update()方法),这个方法叫做更新方法。
- 具体主题(ConcreteSubject):就是你所关注的具体博主(如果你关注了我这个类就是acelit-cnblog),继承自抽象博客,ConcreteSubject将有关状态存入具体现察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。
- 具体观察者(ConcreteObserver):也就是关注博客的读者,继承自抽象观察者,ConcreteObserver存储与主题的状态自恰的状态。具体观察者实现抽象观察者所要求的更新接口,以便使本身的状态与主题的状态相协调。
这么说大家可能还不太理解,结合下面这张图和实现代码来分析:
观察者模型所需4大类(obsever.h):
1 #include <iostream> 2 #include <string> 3 #include <list> 4 #include <iterator> 5 using namespace std; 6 //观察者 7 class Observer 8 { 9 public: 10 Observer() {} 11 virtual ~Observer() {} 12 virtual void Update() {} 13 }; 14 //博客 15 class Blog 16 { 17 public: 18 Blog() {} 19 virtual ~Blog() {} 20 void Attach(Observer *observer) { m_observers.push_back(observer); } //添加观察者 21 void Remove(Observer *observer) { m_observers.remove(observer); } //移除观察者 22 void Notify() //通知观察者 23 { 24 list<Observer*>::iterator iter = m_observers.begin(); 25 for (; iter != m_observers.end(); iter++) 26 (*iter)->Update(); 27 } 28 virtual void SetStatus(string s) { m_status = s; } //设置状态 29 virtual string GetStatus() { return m_status; } //获得状态 30 private: 31 list<Observer* > m_observers; //观察者链表 32 protected: 33 string m_status; //状态 34 }; 35 36 //具体博客类 37 class CNBlog : public Blog 38 { 39 private: 40 string m_name; //博主名称 41 public: 42 CNBlog(string name) : m_name(name) {} 43 ~CNBlog() {} 44 void SetStatus(string s) { m_status = "cnblog通知 : " + m_name + s; } //具体设置状态信息 45 string GetStatus() { return m_status; } 46 }; 47 //具体观察者 48 class ObserverBlog : public Observer 49 { 50 private: 51 string m_name; //观察者名称 52 list<Blog* > m_blog; //订阅者链表 53 public: 54 ObserverBlog(string name) : m_name(name){} 55 ~ObserverBlog() {} 56 void Attach(Blog *blog) { m_blog.push_back(blog); } //添加订阅者 57 void Remove(Blog *blog) { m_blog.remove(blog); } //移除订阅者 58 void Update() //获得更新状态 59 { 60 //为了防止订阅者重复输出所观察的博客,每次只输出最后一个博主的更新消息 61 list<Blog*>::iterator iter = m_blog.end(); 62 string status = (*(--iter))->GetStatus(); 63 if (status != "") 64 cout << m_name << "-------" << status << endl; 65 } 66 };
测试代码:
1 //测试代码 2 //3个观察者,3个订阅者,第1个观测者订阅了1、2、3号订阅者,第1个订阅者被1、2、3号观察者关注。 3 #include "obsever.h" 4 5 int main() 6 { 7 Blog *blog1 = new CNBlog("acelit1"); 8 Blog *blog2 = new CNBlog("acelit2"); 9 Blog *blog3 = new CNBlog("acelit3"); 10 11 ObserverBlog *observer1 = new ObserverBlog("subscriber1"); 12 ObserverBlog *observer2 = new ObserverBlog("subscriber2"); 13 ObserverBlog *observer3 = new ObserverBlog("subscriber3"); 14 15 observer1->Attach(blog1); 16 observer2->Attach(blog1); 17 observer3->Attach(blog1); 18 19 blog1->Attach(observer1); 20 blog1->Attach(observer2); 21 blog1->Attach(observer3); 22 blog1->SetStatus("发表设计模式C++实现——观察者模式"); 23 blog1->Notify(); 24 25 observer1->Attach(blog2); 26 blog2->Attach(observer1); 27 blog2->SetStatus(" published: observer pattern"); 28 blog2->Notify(); 29 30 observer1->Attach(blog3); 31 blog3->Attach(observer1); 32 blog3->SetStatus(" published: 观察者模式"); 33 blog3->Notify(); 34 35 delete blog1; 36 delete blog2; 37 delete blog3; 38 delete observer1; 39 delete observer2; 40 delete observer3; 41 42 system("pause"); 43 return 0; 44 }
测试结果:
博主acelit1状态改变,observer1~3均更新状态;博主acelit2和acelit3状态改变,只有observer1更新状态。
全文完。欢迎各位老司机批评指正O(∩_∩)O
学到即赚到。