Head First观察者模式qt

类图

在这里插入图片描述
在这里插入图片描述

定义

定义了对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又被称为发布-订阅(Publish/Subscribe)模式,模型-视图(Model/View)模式,源-监听器(Source/Listener)模式,或从属者(Dependents)模式。观察者模式是一种对象行为型的模式。

优缺点

优点:

  1. 具体主题和具体观察者是松耦合关系。
    由于主题(Subject)接口仅仅依赖于观察者(Observer)接口,因此具体主题只是知道它的观察者是实现观察者(Observer)接口的某个类的实例,但不需要知道具体是哪个类。同样,由于观察者仅仅依赖于主题(Subject)接口,因此具体观察者只是知道它依赖的主题是实现主题(subject)接口的某个类的实例,但不需要知道具体是哪个类。
  2. 观察者模式满足“开-闭原则”。
    主题(Subject)接口仅仅依赖于观察者(Observer)接口,这样,我们就可以让创建具体主题的类也仅仅是依赖于观察者(Observer)接口,因此如果增加新的实现观察者(Observer)接口的类,不必修改创建具体主题的类的代码。同样,创建具体观察者的类仅仅依赖于主题(Observer)接口,如果增加新的实现主题(Subject)接口的类,也不必修改创建具体观察者类的代码。

缺点:

如果一个被观察者对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
如果在被观察者之间有循环依赖的话,给观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察者模式时要特别注意这一点。
虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制是观察者知道所观察的对象是怎么发生变化的。

设计原则

在交互的对象之间争取松耦合设计

由于松耦合设计使得对象间的依赖最小化,所以,我们能够创建柔性的oo系统,应对变化的情况,因为对象间的依赖降到了最低。

代码

Subject类:

#ifndef SUBJECT_H
#define SUBJECT_H

#include "observer.h"

class Subject
{
public:
    virtual void registerObserver(Observer *o) = 0;
    virtual void removeObserver(Observer *o) = 0;
    virtual void notifyObservers() = 0;
};

#endif // SUBJECT_H

Observer类:

#ifndef OBSERVER_H
#define OBSERVER_H

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

#endif // OBSERVER_H

DisplayElement类:

#ifndef DISPLAYELEMENT_H
#define DISPLAYELEMENT_H


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

#endif // DISPLAYELEMENT_H

WeatherData类:

#ifndef WEATHERDATA_H
#define WEATHERDATA_H

#include "subject.h"

#include <QVector>

class WeatherData : public Subject
{
public:
    WeatherData();
    void registerObserver(Observer *o) override;
    void removeObserver(Observer *o) override;
    void notifyObservers() override;
    void measurementsChanged();
    void setMeasurements(float temperature, float humidity, float pressure);
private:
    QVector<Observer *> observers;
    float temperature;
    float humidity;
    float pressure;
};

#endif // WEATHERDATA_H

#include "weatherdata.h"

WeatherData::WeatherData()
{

}

void WeatherData::registerObserver(Observer *o)
{
    observers.append(o);
}

void WeatherData::removeObserver(Observer *o)
{
    int i = observers.indexOf(o);
    if(i >= 0) {
        observers.remove(i);
    }
}

void WeatherData::notifyObservers()
{
    for(int i = 0; i < observers.size(); i++) {
        Observer *observer = observers.at(i);
        observer->update(temperature, humidity, pressure);
    }
}

void WeatherData::measurementsChanged()
{
    notifyObservers();
}

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

CurrentConditionsDisplay类:

#ifndef CURRENTCONDITIONSDISPLAY_H
#define CURRENTCONDITIONSDISPLAY_H

#include "observer.h"
#include "displayelement.h"
#include "subject.h"

#include <QDebug>

class CurrentConditionsDisplay : public Observer, public DisplayElement
{
public:
    CurrentConditionsDisplay(Subject *weatherData);
    void update(float temperature, float humidity, float pressure) override;
    void display() override;

private:
    float temperature;
    float humidity;
    Subject *weatherData;
};

#endif // CURRENTCONDITIONSDISPLAY_H

#ifndef CURRENTCONDITIONSDISPLAY_H
#define CURRENTCONDITIONSDISPLAY_H

#include "observer.h"
#include "displayelement.h"
#include "subject.h"

#include <QDebug>

class CurrentConditionsDisplay : public Observer, public DisplayElement
{
public:
    CurrentConditionsDisplay(Subject *weatherData);
    void update(float temperature, float humidity, float pressure) override;
    void display() override;

private:
    float temperature;
    float humidity;
    Subject *weatherData;
};

#endif // CURRENTCONDITIONSDISPLAY_H

ForecastDisplay类:

#ifndef FORECASTDISPLAY_H
#define FORECASTDISPLAY_H

#include "observer.h"
#include "displayelement.h"
#include "subject.h"

#include <QDebug>

class ForecastDisplay : public Observer, public DisplayElement
{
public:
    ForecastDisplay(Subject *weatherData);
    void update(float temperature, float humidity, float pressure) override;
    void display() override;

private:
    float temperature;
    float humidity;
    Subject *weatherData;
};

#endif // FORECASTDISPLAY_H

#include "forecastdisplay.h"

ForecastDisplay::ForecastDisplay(Subject *weatherData)
{
    this->weatherData = weatherData;
    weatherData->registerObserver(this);
}

void ForecastDisplay::update(float temperature, float humidity, float pressure)
{
    this->temperature = temperature;
    this->humidity = humidity;
    display();
}

void ForecastDisplay::display()
{
    qDebug() << "Forecast" << temperature << "F degress and"
             << humidity << "% humidity";
}

StatisicsDisplay类:

#ifndef STATISICSDISPLAY_H
#define STATISICSDISPLAY_H

#include "observer.h"
#include "displayelement.h"
#include "subject.h"

#include <QDebug>

class StatisicsDisplay : public Observer, public DisplayElement
{
public:
    StatisicsDisplay(Subject *weatherData);
    void update(float temperature, float humidity, float pressure) override;
    void display() override;

private:
    float temperature;
    float humidity;
    Subject *weatherData;
};

#endif // STATISICSDISPLAY_H

#include "statisicsdisplay.h"

StatisicsDisplay::StatisicsDisplay(Subject *weatherData)
{
    this->weatherData = weatherData;
    weatherData->registerObserver(this);
}

void StatisicsDisplay::update(float temperature, float humidity, float pressure)
{
    this->temperature = temperature;
    this->humidity = humidity;
    display();
}

void StatisicsDisplay::display()
{
    qDebug() << "Statisics" << temperature << "F degress and"
             << humidity << "% humidity";
}

测试:

#include "mainwindow.h"

#include <weatherdata.h>
#include "currentconditionsdisplay.h"
#include "statisicsdisplay.h"
#include "forecastdisplay.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    WeatherData *weatherData = new WeatherData();
    CurrentConditionsDisplay *currentDisplay = new CurrentConditionsDisplay(weatherData);
    StatisicsDisplay *statisicsDisplay = new StatisicsDisplay(weatherData);
    ForecastDisplay *forecastDisplay = new ForecastDisplay(weatherData);

    weatherData->setMeasurements(80, 65, 30.4);
    weatherData->setMeasurements(82, 70, 29.2);
    weatherData->setMeasurements(78, 90, 29.2);

}

MainWindow::~MainWindow()
{
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
观察者模式是一种常见的设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。在这个模式中,被观察者对象通常称为主题(Subject),而观察者对象通常称为观察者(Observer)。 下面我们就以一个简单的天气预报系统为例来介绍观察者模式的使用。 首先,我们需要定义一个主题接口(Subject),它包含了添加、删除和通知观察者的方法: ```java public interface Subject { public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObservers(); } ``` 然后,我们需要定义一个观察者接口(Observer),它包含了更新数据的方法: ```java public interface Observer { public void update(float temp, float humidity, float pressure); } ``` 接下来,我们需要定义一个具体的主题类(WeatherData),它实现了主题接口,并包含了一个列表来存储观察者对象,以及当前的温度、湿度和气压等数据: ```java import java.util.ArrayList; public class WeatherData implements Subject { private ArrayList<Observer> observers; private float temperature; private float humidity; private float pressure; public WeatherData() { observers = new ArrayList<Observer>(); } public void registerObserver(Observer o) { observers.add(o); } public void removeObserver(Observer o) { int i = observers.indexOf(o); if (i >= 0) { observers.remove(i); } } public void notifyObservers() { for (int i = 0; i < observers.size(); i++) { Observer observer = (Observer)observers.get(i); observer.update(temperature, humidity, pressure); } } public void measurementsChanged() { notifyObservers(); } public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } // other WeatherData methods here } ``` 最后,我们需要定义一个具体的观察者类(CurrentConditionsDisplay),它实现了观察者接口,并在更新数据时打印出当前的温度、湿度和气压等信息: ```java public class CurrentConditionsDisplay implements Observer { private float temperature; private float humidity; private Subject weatherData; public CurrentConditionsDisplay(Subject weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } public void update(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; display(); } public void display() { System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity"); } } ``` 现在,我们可以创建一个天气预报系统,它包含了一个主题对象和一个观察者对象,并通过调用主题对象的方法来更新数据和通知观察者: ```java public class WeatherStation { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); weatherData.setMeasurements(80, 65, 30.4f); weatherData.setMeasurements(82, 70, 29.2f); weatherData.setMeasurements(78, 90, 29.2f); } } ``` 以上就是一个简单的观察者模式的例子,它可以让我们更好地理解和应用这个常见的设计模式

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值