设计模式入门(二)观察者模式

这篇具有很好参考价值的文章主要介绍了设计模式入门(二)观察者模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

设计模式入门

本系列所有内容参考自《HeadFirst设计模式》。因为书中的代码是采用java语言写的,博主这里用C++语言改写。
这里采用讲故事的方式进行讲解。若有错误之处,非常欢迎大家指导。
设计模式:模式不是代码,而针对设计问题的通用解决方案,被认为是历经验证的OO设计经验。设计模式告诉我们如何组织类和对象以解决某种问题。
如果你输出一个helloworld都想使用设计模式的话,那可能真的就有问题了。

正文

提出问题

我们现在手头有一个气象检测应用。气象站接收湿度感应装置温度感应装置气压感应装置的数据,然后我们有一个WeatherData对象,它负责追踪来自气象站的数据,并更新布告板(显示目前天气状况给用户看)。
设计模式入门(二)观察者模式,设计模式,设计模式,观察者模式,C++
如果我们要接手这个项目,我们的工作就是建立一个应用,利用WeatherData对象取得数据,并更新三个布告板:目前状况、气象统计和天气预报。三个布告板如下图所示:
设计模式入门(二)观察者模式,设计模式,设计模式,观察者模式,C++

现有的WeatherData类源码如下:

class WeatherData {
    float getTemperature();  //返回温度
    float getHumidity();     //返回湿度
    float getPressure();     //返回气压
    void measurementsChanged()
    {
        /*一旦气象测量更新,此方法会被调用*/
        //我们的代码加在这里
    }
};

我们的工作是实现measurementsChanged(),好让它更新目前状况、气象统计、天气预报的显示布告板。

我们目前知道的:WeatherData类有三个方法,可以取得三个测量值;当新的数据来临时,measurementsChanged()方法就会被调用(我们不在乎此方法是如何被调用的,我们只在乎它被调用了);我们需要实现三个使用天气数据的布告板,一旦WeatherData有新的测量,这些布告必须马上更新。

一个我们可能想到的measurementsChanged()实现如下:

class WeatherData {
	// 实例变量声明
    void measurementsChanged()
    {
    	// 获取最新的测量值
        float temp = getTemperature();
        float humidity = getHumidity();
        float pressure = getPressure();
        
        // 调用每个布告板更新显示
        currtenConditionsDisplay.update(temp, humidity, pressure);  // 目前状况布告板更新
        statisticsDisplay.update(temp, humidity, pressure);  // 气象统计布告板更新
        forecastDisplay.update(temp, humidity, pressure);   // 天气预报布告板更新
    }
};

但是这与一些软件设计原则发生了矛盾。上面代码中调用每个布告板更新显示函数是针对具体实现编程,会导致我们以后在增加或删除布告板时必须修改程序;三个接口都是update,传入的参数也是一样的,所以看起来更像是一个统一的接口。

那我们该如何解决这个问题呢?观察者模式可以帮助我们很好地解决这个问题。

观察者模式

一个很简单的例子就是杂志订阅
假设我们订阅了一款杂志,每当这款杂志更新时,它都会给我们送一份。这就是观察者模式,杂志相当于“主题”,我们相当于“观察者”,当主题发生改变时,就是通知“观察者”。这里要注意的一点是:主题来增加或删除观察者。 还是杂志订阅这个问题,我们想订阅杂志的时候,杂志出版社便会将我们加到它们的订阅名单里,我们不想订阅杂志时,杂志出版社便会将我们从订阅名单里删除。

观察者模式:观察者模式定义了对象之间的一对多依赖(“一个主题”对“多个观察者”),这样一来,当一个对象改变状态时,它的所有依赖者(因为主题是真正拥有数据的人,观察者是主题的依赖者)都会收到通知并自动更新。

实现代码如下:

#include<iostream>
#include<vector>

using namespace std;

class Observer {  // 观察者
public:
    virtual void update(float temp, float humidity, float pressure) = 0;
};

class Subject {  // 抽象主题
    virtual void registerObserver(Observer *o)=0;
    virtual void removeObserver(Observer *o)=0;
    virtual void notifyObserver()=0;
};

class DisplayElement {
    virtual void display()=0;
};

class WeatherData : public Subject  // 具象主题
{
private:
    vector<Observer*> observers;
    float temperature;
    float humidity;
    float pressure;
public:
    void registerObserver(Observer *o)  // 注册观察者
    {
        observers.push_back(o);
    }

    void removeObserver(Observer *o)   // 取消观察者
    {
        auto it = std::find(observers.begin(), observers.end(), o);

        if (it != observers.end())
        {
            int index = std::distance(observers.begin(), it);
            cout << "索引是:" << index << endl;;
            observers.erase(observers.begin() + index);
            cout << "成功删除元素" << endl;
        }
        else
        {
            cout << "未找到元素" << endl;
        }
    }

    void notifyObserver()  // 通知观察者
    {
        for (int i = 0; i < observers.size(); i++)
        {
            Observer *observer = observers[i];
            observer->update(temperature, humidity, pressure);
        }
    }
    void measurementsChanged()
    {
        notifyObserver();  // 通知观察者
    }

    void setMeasurements(float temperature, float humidity, float pressure)
    {
        this->temperature = temperature; 
        this->humidity = humidity;
        this->pressure = pressure;
        measurementsChanged();
    }
};

class StatisticsDisplay : public Observer, public DisplayElement  // 观察者
{
private:
    float temperature;
    float humidity;
    WeatherData *weatherData;
public:
    StatisticsDisplay(WeatherData *weather)
    {
        weatherData = weather;
        weatherData->registerObserver(this);  //主题注册观察者
    }

    void remove()
    {
        weatherData->removeObserver(this); // 主题取消观察者
    }

    void update(float temperature, float humidity, float pressure)
    {
        this->temperature = temperature;
        this->humidity = humidity;
        display();
    }
    void display()
    {
        cout << "statisticsDisplay: " << temperature << "F degress and " << humidity << "% humidity" << endl;
    }
};

class ForecastDisplay : public Observer, public DisplayElement  // 观察者
{
private:
    float temperature;
    float humidity;
    WeatherData *weatherData;
public:
    ForecastDisplay(WeatherData *weather)
    {
        weatherData = weather;
        weatherData->registerObserver(this);  //主题注册观察者
    }

    void remove()
    {
        weatherData->removeObserver(this); // 主题取消观察者
    }

    void update(float temperature, float humidity, float pressure)
    {
        this->temperature = temperature;
        this->humidity = humidity;
        display();
    }
    void display()
    {
        cout << "ForecastDisplay: " << temperature << "F degress and " << humidity << "% humidity" << endl;
    }
};

class CurrentConditionsDisplay : public Observer, public DisplayElement  // 观察者
{
private:
    float temperature;
    float humidity;
    WeatherData *weatherData;
public:
    CurrentConditionsDisplay(WeatherData *weather)
    {
        weatherData = weather;
        weatherData->registerObserver(this);  //主题注册观察者
    }

    void remove()
    {
        weatherData->removeObserver(this); // 主题取消观察者
    }

    void update(float temperature, float humidity, float pressure)
    {
        this->temperature = temperature;
        this->humidity = humidity;
        display();
    }
    void display()
    {
        cout << "CurrentConditionsDisplay: " << temperature << "F degress and " << humidity << "% humidity" << endl;
    }
};
int main()
{
    WeatherData *weatherData = new WeatherData; // 定义一个主题对象即可
    CurrentConditionsDisplay currentDisplay(weatherData);  // 第一个观察者
    StatisticsDisplay statisDisplay(weatherData);   // 第二个观察者
    ForecastDisplay foreDisplay(weatherData);   // 第三个观察者
    weatherData->setMeasurements(80, 65, 30.4);   // 主题信息发生变更
    
    currentDisplay.remove();   // 该观察者取消对主题的订阅

    weatherData->setMeasurements(40, 25, 15.4);

    foreDisplay.remove();   // 该观察者取消对主题的订阅

    weatherData->setMeasurements(15.5, 26, 34);
    return 0;
}

以上就是使用C++实现观察者模式的全部代码。

设计原则

  1. 找出程序中会变化的方面,然后将其和固定不变的方面相分离。
    在观察中模式中,会改变的是主题的状态,以及观察者的数目和类型。用这个模式,你可以改变依赖于主题状态的对象,却不必改变主题。
  2. 针对接口编程,不针对实现编程。
    主题与观察者都是用接口:观察者利用主题的接口向主题注册,而主题利用观察者接口通知观察者。这样可以让两者之间运作正常,又同时具有松耦合的优点。

观察者模式较为重要,在很多软件框架和软件设计中都可以看到它的身影,所以大家可以根据代码仔细体会它的思想。工作的那几个月在公司的软件里看到过观察者模式,但是没有自己动手实现,只是明白它的意思。今天自己动手实现了一下,感悟又深了一些。文章来源地址https://www.toymoban.com/news/detail-694439.html

到了这里,关于设计模式入门(二)观察者模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 设计模式——观察者模式

    观察者模式可以分为观察者和被观察者,观察者通过注册到一个被观察者中,也可视为订阅,当被观察者的数据发生改变时,会通知到观察者,观察者可以据此做出反应。 可以类比订阅报纸,报社就是被观察者,订阅者就是观察者,订阅者通过订阅报纸与报社建立联系,而报

    2024年02月15日
    浏览(39)
  • 设计模式——14. 观察者模式

    观察者模式(Observer Pattern)是一种行为型设计模式,用于定义对象之间的一对多依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都能够自动收到通知并更新自己的状态,以保持与被观察对象的同步。观察者模式也被称为发布-订阅模式。 观察者模式包含以

    2024年02月07日
    浏览(35)
  • 重温设计模式 --- 观察者模式

    观察者模式 是一种行为型设计模式,它允许对象之间建立一种一对多的关系,使得当一个对象状态改变时,所有依赖它的对象都能够自动得到通知并更新自己的状态。该模式可以帮助我们实现松耦合的系统,以便更好地应对变化和扩展。 在观察者模式中,有两个角色: 观察

    2024年02月13日
    浏览(44)
  • 设计模式(11)观察者模式

    一、概述: 1、定义:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。 2、结构图: 实现  调用

    2024年02月11日
    浏览(38)
  • 设计模式之观察者模式

    可以帮你的对象知悉现况,不会错过该对象感兴趣的事。对象甚至在运行时可决定是否要继续被通知。 从报纸和杂志的订阅说起: 报社的业务就是出版报纸 向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。只要你是他们的订户,你就会一直收到新报纸。 当你不

    2024年01月24日
    浏览(42)
  • 设计模式-观察者

    观察者模式是一种广泛应用于软件开发中的行为设计模式,尤其是在面向对象编程(OOP)中。该模式定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新 在观察者模式中,存在两个主要角色: 主题(Subject) 或 被

    2024年01月22日
    浏览(34)
  • 观察者设计模式

    行为型模式(Behavioral Patterns):这类模式主要关注对象之间的通信。它们 分别是: 职责链模式(Chain of Responsibility) 命令模式(Command) 解释器模式(Interpreter) 迭代器模式(Iterator) 中介者模式(Mediator) 备忘录模式(Memento) 观察者模式(Observer) 状态模式(State) 策略

    2024年01月24日
    浏览(37)
  • 设计模式:行为型模式 - 观察者模式

    定义: 又被称为发布-订阅(Publish/Subscribe)模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。 在观察者模式中有如下角色: Subject:抽象主题(抽象被观察

    2023年04月22日
    浏览(85)
  • 设计模式之二:观察者模式

    假定我们需要为Weather-O-Rama公司建立一个气象站系统,除已有的WeatherData有数据源类,还需要更新三个布告板的显示:目前状况(温度、湿度、气压)、气象统计和天气预报。  1 以下是一个可能的实现 上述实现有以下问题存在: 针对具体实现编程,而非针对接口(currentCon

    2024年02月13日
    浏览(23)
  • Java 设计模式——观察者模式

    观察者模式 (Observer Pattern) 是一种行为型设计模式,又被称为发布-订阅 (Publish/Subscribe) 模式, 它定义了对象之间的一种一对多的依赖关系,使得当一个对象的状态发生变化时,所有依赖于它的对象都会自动收到通知并更新 。 在观察者模式中有如下角色: Subject:观察对象 ,

    2024年02月16日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包