设计模式之观察者模式

来源:互联网 发布:淘宝上买的车衣不耐用 编辑:程序博客网 时间:2024/04/23 14:11

设计模式之观察者模式

         观察者模式定义了一系列对象之间的一对多的关系,当一个对象的状态发生变化时,他的所有依赖者都会受到通知并自动更新。

         观察者模式利用了“为了交互对象之间的松耦合设计努力”的设计原则。松耦合设计将对象的互相依赖降低到最低。其对象模型如下:

        

观察者模式中两个对象之间是松耦合的,它们依然可以交互,但是不清楚彼此之间的实现细节。使用观察者模式中,主题是具有状态的对象,并且可以控制这些状态,也就是说主题是一个具有状态的主题。而观察者使用这些状态,虽然这些状态不属于它们,它们依赖主题告诉它们状态何时改变了,并做相应的更新处理,这就产生了一个主题对多个观察者的关系。主题是拥有数据的人,观察者是使用这些数据的人,这样的设计要比多个对象同时控制一份数据更干净。

什么时候使用观察者模式:

1) 当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。

2) 当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。

3) 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。

其实观察者模式同策略模式有着共同的使用环境:将变化独立封装起来,以达到最大的重用和解耦。不同的地方在于,观察者模式中的目标和观察者的变化不是独立的,而是有着某些联系。

用书中的气象站举个例子,用C++实现

首先定义主题接口和观察者接口:

//defineinterface

class Observer

{

public:

    virtual void Update(float temp, float humidity, float pressure) = 0;

};

 

class DisplayElement

{

public:

    virtual void Display() = 0;

};

 

class Subject

{

public:

    virtual void RegisterObserver(Observer* ob) = 0;

    virtual void RemoveObserver(Observer* ob) = 0;

    virtual void NotifyObserver()= 0;

private:

};

实现“主题”气象站:

#include "interface.h"

#include <list>

using namespace std;

class WeatherSubject: publicSubject

{

private:

     list<Observer*>ObseverList;

     float temperature;

     float humidity;

     float pressure;

 

public:

     WeatherSubject(){

         ObseverList.clear();

         temperature = 0;

         humidity =0;

         pressure =0;

     }

 

     void RegisterObserver(Observer* ob){

         ObseverList.push_back(ob);

     }

 

     void RemoveObserver(Observer* ob)

     {

         list<Observer*>::iterator Obiter;

         for (Obiter = ObseverList.begin();Obiter != ObseverList.end(); Obiter++)

         {

              if (ob == *Obiter)

              {

                   break;

              }

         }

         if (Obiter != ObseverList.end())

         {

              ObseverList.erase(Obiter);

         }

     }

    

     void NotifyObserver()

     {

         list<Observer*>::iterator iter;

         for (iter=ObseverList.begin();iter != ObseverList.end(); iter++)

         {

              (*iter)->Update(temperature,humidity,pressure);

         }

     }

 

     void SetMeasurements(float temperature,float humidity, float pressure)

     {

         this->temperature= temperature;

         this->humidity    = humidity;

         this->pressure    = pressure;

         NotifyObserver();

     }

};

实现“观察者”气象显示对象:

#include "interface.h"

#include <iostream>

using namespacestd;

 

class CurrentConditionsDisplay: public Observer,public DisplayElement

{

private:

    float temperature;

    float humidity;

    Subject* weatherData;

 

public:

    CurrentConditionsDisplay(Subject* weatherData)

    {

        this->weatherData = weatherData;

        weatherData->RegisterObserver(this);

    }

   

    void Update(float temp,float humidity, float pressure)

    {

        this->temperature = temp;

        this->humidity    = humidity;

        Display();

    }

     

    void Display()

    {

        cout<<"Current Conditions: "<<temperature<<"Fdegrees and "<<humidity<<"% humdity"<<endl;

    }

};

在main函数中使用上述两个类,实现动态更新气象信息,自动显示:

#include "display.h"

#include "weatherdata.h"

 

int main()

{

    WeatherSubjectweather;

    CurrentConditionsDisplaycurrentDisplay(&weather);

    weather.SetMeasurements(80,65,34.5f);

    return 0;

}

         在C语言中也经常用到观察者模式,例如A模块的处理依赖B模块的状态,当B模块状态发生变化时需要通知A模块做相应的处理,在C语言中一般会使用钩子函数实现,B模块定义一个函数指针void (*func)()和一个注册函数接口Register(Func f),在这个注册函数中B模块将函数指针参数保存到函数指针队列中,当B模块状态变化的模块调用这些函数,从而达到了状态通知的目的;

         观察者模式存在“推数据”和“拉数据”两种实现方式,也就当主题对象的状态发生变化时是主动将全部数据通知给观察者还是只是通知观察者数据发生了变化,由观察者自己调用接口来获取数据。