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

定义

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

要点

  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 = -Wall
LDFLAGS = 

target = res
srcs = main.cpp
objs = $(srcs:.cpp=.o)

.PHONY: all
all: $(target)

$(target): $(objs)
    $(CXX) $(LDFLAGS) -o $(target) $^

$(objs):%.o:%.cpp
    $(CXX) $(CFLAGS) -c -o $@ $<

clean:
    rm -f $(target) *.o

测试

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值