C++设计模式二--OberverPattern(观察者模式)

来源:互联网 发布:ubuntu 设置ntp客户端 编辑:程序博客网 时间:2024/05/21 12:50

定义

  观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖者都会收到通知并自动更新。

要点

  1)观察者模式定义了对象之间的一对多的关系。
  2)主题(被观察者)用一个共同接口(Observer)来更新观察者。
  3)观察者和被观察者之间用松耦合方式结合,被观察者不知道观察者的细节,只知道观察者实现了观察者接口。
  4)使用此模式,可以从被观察者车推(push)或拉(pull)数据(然而,推的方式被认为更“正确”)。
  5)有多个观察者是,不可以依赖特定的通知次序。

类图

这里写图片描述
Subject:主题接口,对象使用此接口注册为观察者,或者把自己从观察者中删除。
Oberver:所有的观察者必须实现观察者接口,这个接口只有update()一个方法,当主题状态改变时会被调用。
ConcreteSubject:主题,必须实现主题接口的三个方法,当主题状态变化是通过notifyObserver()方法更新所有观察者。
concreteOberver:具体观察者,可以是实现此接口的任意类。观察者必须注册具体主题,以便接收更新。

设计原则

  为了交互对象之间的松耦合设计而努力。
 
松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的互相依赖降到了最低。

  1)关于观察者,主题之知道观察者实现了某个接口(Observer接口)。主题不需要知道观察者的具体类是谁、做了写什么活着其他任何细节。
  2)任何时候都可以增加新的观察者。
  3)任何时候都可以删除或者取代某个或者某些观察者。
  4)当有新的观察者出现时,主题代码不需要修改。只需要新的观察者实现此观察者接口(Observer接口),然后注册为观察者即可。
  5)改变主题或观察者其中一方,并不影响另一方。因为两者是松耦合,只要他们之间的接口仍被遵守,我们就可以自由的改变他们。

示例 

  现在通过实现一个气象站示例。当气象站的状态发生变化是,需要通知不同的布告板来更新状态,如下为代码:

Subject.h

#ifndef SUBJECT_H#define SUBJECT_H#include "Observer.h"/*** 主题(被观察者)接口*/class Subject {public:     virtual ~Subject(){}    virtual void registerObserver(Observer* o) = 0;    virtual void removeObserver(Observer* o) = 0;    virtual void notifyObserver() = 0;};#endif

WeatherData.h

#ifndef WEATHERDATA_H#define WEATHERDATA_H#include "Observer.h"#include "Subject.h"#include <list>using namespace std;/*** 气象站(被观察者实例,一般只有一个)*/class WeatherData : public Subject {private:    list<Observer*> m_observers;    float m_temperature;    float m_humidity;    float m_pressure;public:     WeatherData(){}    void registerObserver(Observer* o)    {        m_observers.push_back(o);    }    void removeObserver(Observer* o)    {        // 从m_observers列表中删除o        list<Observer*>::iterator i;        for (i=m_observers.begin(); i!=m_observers.end(); i++) {            if (*i == o) {                m_observers.erase(i++);            }        }    }    void notifyObserver()    {        list<Observer*>::iterator i;        Observer* observer;        for (i=m_observers.begin(); i!=m_observers.end(); i++) {            // 调用每一个观察者的update方法            observer = *i;            observer->update();        }    }    float getTemperature()    {        return m_temperature;    }    float getHumidity()    {        return m_humidity;    }    float getPressure()    {        return m_pressure;    }    void measurementChanged()    {        notifyObserver();    }    void setMeasurements(float temp, float humidity, float pressure)    {        this->m_temperature = temp;        this->m_humidity = humidity;        this->m_pressure = pressure;        measurementChanged();    }    // WeatherData的其他方法};#endif

Oberver.h

#ifndef OBSERVER_H#define OBSERVER_H/*** 观察者接口*/class Observer {public:    virtual ~Observer(){}    virtual void update() = 0;};#endif

CurrentConditionsDisplay.h

#ifndef CURRENTCONDITIONSDISPLAY_H#define CURRENTCONDITIONSDISPLAY_H#include "WeatherData.h"#include "Observer.h"#include "Subject.h"#include <iostream>using std::cout;/*** 显示目前状况(观察者实例,有多个)*/class CurrentConditionsDisplay : public Observer {private:    float m_temperature;    float m_humidity;    Subject* m_weatherData; public:    CurrentConditionsDisplay(Subject* weatherData)    {        this->m_weatherData = weatherData;        weatherData->registerObserver(this);    }    void update()    {        WeatherData* weatherData = dynamic_cast<WeatherData*>(this->m_weatherData);        if (weatherData) {            this->m_temperature = weatherData->getTemperature();            this->m_humidity = weatherData->getHumidity();            display();        }    }    void display()    {        cout << "corrent conditions:";        cout << "temperature:" << m_temperature ;        cout << " humidity:" << m_humidity << "%" << endl;    }};#endif

TemperatureOnlyDisplay.h

#ifndef __TEMPERATUREONLYDISPLAY_H__#define __TEMPERATUREONLYDISPLAY_H__#include "WeatherData.h"#include "Observer.h"#include "Subject.h"#include <iostream>using std::cout;using std::endl;class TemperatureOnlyDisplay : public Observer{public:    TemperatureOnlyDisplay(Subject* wd)    {        m_weatherData = wd;        wd->registerObserver(this);    }    void update()    {        WeatherData* weatherData = dynamic_cast<WeatherData*>(this->m_weatherData);        temp = weatherData->getTemperature();        display();    }    void display()    {        cout << "TemperatureOnlyDisplay displaying, ";        cout << "Temperuture: " << temp << endl;        cout << endl;    }private:    Subject *m_weatherData;    int temp;    int humidity;    int pressure;};#endif

main.cpp

#include <iostream>#include "WeatherData.h"#include "CurrentConditionsDisplay.h"#include "TemperatureOnlyDisplay.h"using namespace std;int main(){    WeatherData* weatherData = new WeatherData();    CurrentConditionsDisplay* currentDisplay = new CurrentConditionsDisplay(weatherData);    TemperatureOnlyDisplay* temperatureDisplay = new TemperatureOnlyDisplay(weatherData);    weatherData->setMeasurements(80, 65, 30.4);    weatherData->removeObserver(currentDisplay);    weatherData->setMeasurements(88, 55, 36.4);    delete temperatureDisplay;    delete currentDisplay;    delete weatherData;    return 0;}

Makefile

CXX = g++CFLAGS = -WallLDFLAGS = target = ressrcs = main.cppobjs = $(srcs:.cpp=.o).PHONY: allall: $(target)$(target): $(objs)    $(CXX) $(LDFLAGS) -o $(target) $^$(objs):%.o:%.cpp    $(CXX) $(CFLAGS) -c -o $@ $<clean:    rm -f $(target) *.o

测试

测试结果如下所示:
这里写图片描述

本文完整代码下载地址:https://github.com/zhaoxd298/ObserverPattern