设计模式之观察者模式

一、什么是观察者模式

     Observer模式也叫观察者模式,是由GoF提出的23种软件设计模式的一种。Observer模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。

  观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。

 

  观察者模式有很多实现方式,从根本上说,该模式必须包含两个角色:观察者和被观察对象。在刚才的例子中,业务数据是被观察对象,用户界面是观察者。观察者和被观察者之间存在“观察”的逻辑关联,当被观察者发生改变的时候,观察者就会观察到这样的变化,并且做出相应的响应。如果在用户界面、业务数据之间使用这样的观察过程,可以确保界面和数据之间划清界限,假定应用程序的需求发生变化,需要修改界面的表现,只需要重新构建一个用户界面,业务数据不需要发生变化。

 

  “观察”不是“直接调用”

  实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。无论是观察者“观察”观察对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。

 

  实现观察者模式的形式

  实现观察者模式有很多形式,比较直观的一种是使用一种“注册——通知——撤销注册”的形式。

 

   实现观察者模式例子

       下面是C++的实现,在C++实现中,C++中没有接口的概念,但是可以用抽象类类代替Java或C#中的接口,在C++中抽象类中从派生类中抽象出来的函数(方法),必须定义成纯虚函数,这样在后面的使用中才可以通过基类的指针来访问这些函数,面向对象的语言中有个特点,多态只能访问两者中共有的部分。

  1
  2#include "stdafx.h"
  3#include <string>
  4#include <vector>
  5#include<list>
  6#include<iostream>
  7using namespace std;
  8
  9class Observer;
 10class Subject
 11{
 12public:
 13    //注册
 14     virtual void attach(Observer *o)=0;
 15     //撤销
 16     virtual void dettach(Observer *o)=0;
 17     //发送消息,更新观察者数据
 18     virtual void change()=0;
 19     //更新数据
 20     virtual void setWeather(string str)=0;
 21     //获取数据
 22     virtual string getWeather()=0;
 23}
;
 24
 25class Observer
 26{
 27public:
 28    //获得观察者的名字,用于后面dettach撤销操作
 29     virtual string getName()=0;
 30     //更新数据,用于被观察者调用
 31     virtual void update(Subject *s)=0;
 32}
;
 33
 34//被观察者
 35class Earth: public Subject
 36{
 37private:
 38    //数据
 39     string weather;
 40     //存放观察者的list,因为Observer是个抽象类,
 41     //所以不能声明成 list<Observer >* l
 42     list<Observer* >* l;//指针 
 43public:
 44    //初始化存放观察者的容器
 45     Earth()
 46     {
 47        l = new list<Observer*>;
 48     }
;
 49     //别忘了释放资源
 50    ~Earth()
 51    {
 52        delete l;
 53    }
;
 54    //注册观察者
 55     void attach(Observer *o)
 56     {
 57        this->l->push_back(o);
 58     }
;
 59    
 60     //注销观察者
 61      void dettach(Observer *o)
 62     {
 63         for(list<Observer*>::iterator it=l->begin();it!=l->end();++it)
 64         {
 65             //通过string来进行查找,其他通过指针怎么判断相等比较困难
 66             if( (*it)->getName() == o->getName())
 67             {
 68                 l->remove(*it);
 69                 break;
 70             }

 71         }

 72     }
;
 73
 74    //通知并更新观察者
 75     void change()
 76     {
 77          for(list<Observer*>::iterator it=l->begin();it!=l->end();++it)
 78          {
 79            (*it)->update(this);
 80          }

 81     }
;
 82
 83     //更新数据
 84     void setWeather(string str)
 85     {
 86          this->weather=str;
 87          change();
 88     }
;
 89
 90     string getWeather()
 91     {
 92         return this->weather;
 93     }
;
 94
 95}
;
 96
 97class Satellite:public Observer
 98{
 99private:
100     string name;
101public:
102     Satellite(string str)
103     {
104          name=str;
105     }

106     string getName()
107     {
108         return name;
109     }
;
110     //更新数据
111     void update(Subject *s)
112     {
113         cout<<this->getName()+" "+s->getWeather()<<endl;
114     }

115}
;
116
117
118
119int _tmain(int argc, _TCHAR* argv[])
120{
121     Earth e;
122     Satellite *s1 = new Satellite("风云一号");
123     Satellite *s2 = new Satellite("风云二号");
124     Satellite *s3 = new Satellite("风云三号");
125     Satellite *s4 = new Satellite("风云四号");
126     e.attach(s1);
127     e.attach(s2);
128     e.attach(s3);
129     e.attach(s4);
130     e.setWeather("fine");
131     e.setWeather("rain");
132     //注销s3
133     e.dettach(s3);
134     e.setWeather("fine");
135     e.setWeather("rain");
136
137
138    return 0;
139}

140
141

以上文字参照http://blog.csdn.net/preciousboy/article/details/6230467,对其代码进行修改在vs2008中编译调试通过。
结果运行为:


这里要注意的几个问题是?
1.被观察者怎么去通知观察者数据已经更新?--本例子中是通过void change()函数来实现的;
2.在此模式中你可以从被观察者处push或者pull数据,我们认为push的方式是正确的。
3.观察者模式定义了一对多的关系
4.有多个观察者时不依赖于特定的通知次序。
5.java的MVC模式就采用此模式实现。

posted on 2012-05-01 11:47 sheng 阅读(636) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理


导航

<2012年5月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

统计

常用链接

留言簿(1)

随笔档案

收藏夹

同行

搜索

最新评论

阅读排行榜

评论排行榜