窥探观察者模式

  观察者模式(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

 

posted @ 2016-12-18 18:42  Acelit  阅读(773)  评论(0编辑  收藏  举报