设计模式(二)之观察者模式

场景描述

今天,我们接到一个需求。我们气象局需要给某个app提供一个接口。我们气象局通过各种感应装置,能够查到温度、湿度和气压等数据并且更新到三个不同的布告板上面。

分析

三个布告板需要三项数据,那么这个类weatherData类需要实现三个get,分别是getTEmperature、getHumidity和getPressure获取三项数据。然后通知给三个布告板,我们气象局数据已经更新了,需要创建一个方法measurementsChanged。获取三项数据十分简单,但是我们应该如何去实现这个通知方法呢?

设计

我们已经的到的方法
1.get方法
2.更新的时候触发measurementsChanged方法
然后,我们需要实现布告板以显示更新后的数据display。我们的布告板是需要可扩展的,因为在未来可能不止三个布告板,我们应该是可以新增加的。

错误实现

我们很容易想到是不是我们可以在measurementsChanged方法里面,手动获取到三项数据然后手动更新到布告板的类上面?


image.png

改变的地方,需要封装气啦

如果像上面一样的话,代码就变死了,因为它不具备可扩展性。我们可以看到三个布告板调用的方法貌似有点相似,甚至可以说一模一样。其实我们就可以抽象为接口,这样的话我们就可以面向接口编程,利用多态的特性,来遍历即可。

观察者模式

描述

在这里我们的weatherData就是下图的主题,各种对象就是我们的观察者。当数据改变的时候,主题就会通知观察者。
过程
1.主题对象需要管理这些观察者对象。(可以联想到你去报刊社订阅报刊,报刊社就会有记录,里面有很多订阅者的信息)
2.当主题对象改变的时候,主题就会把信息推送给观察者(报刊社送新一期的杂志给你)
3.没有注册的对象就不是观察者,那么在推送的时候,自然也不会推送给这些对象。


image.png

具体定义

定义了对象之间的一对多依赖,这样一来,当对象改变状态的时候,它的所有依赖者都会收到通知并更新。


image.png

实现类图

image.png

为了交互对象之间的松耦合设计而努力。

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

设计气象站

image.png

代码实现

主题

package com.yyh.observer;

/**
 * 主题
 */
public interface Subject {
    /**
     * 注册观察者
     * @param observer
     */
    public void registerObserver(Observer observer);

    /**
     * 移除观察者
     * @param observer
     */
    public void removeObserver(Observer observer);

    /**
     * 通知观察者
     */
    public void notifyObserver();



}

观察者

package com.yyh.observer;

/**
 * 观察者
 */
public interface Observer {
    /**
     * 更新观察者
     * @param temperature
     * @param humidity
     * @param pressure
     */
    public void update(float temperature,float humidity,float pressure);
}


显示接口

方便以后,统一遍历。当然在这个例子里面可有可无

package com.yyh.observer;

/**
 * 观察者
 */
public interface Observer {
    /**
     * 更新观察者
     * @param temperature
     * @param humidity
     * @param pressure
     */
    public void update(float temperature,float humidity,float pressure);
}


主题实现---weatherData

package com.yyh.observer;

import java.util.ArrayList;
import java.util.List;

public class WeatherData implements Subject {
    //存储所有的观察者,注意类型是observer,里面有方法update
    private List observers;
    private float temperature;
    private float humidity;
    private float pressure;

    /**
     * 初始化list,方便存储
     */
    public WeatherData() {
        this.observers = new ArrayList<>();
    }

    /**
     * 注册观察者
     * @param observer
     */
    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    /**
     * 删除观察者
     * @param observer
     */
    @Override
    public void removeObserver(Observer observer) {
        int i = observers.indexOf(observer);
        if (i>0){
            observers.remove(observer);
        }
    }

    /**
     * 通知观察者
     */
    @Override
    public void notifyObserver() {
        for (int i = 0; i < observers.size(); i++) {
            Observer temp = observers.get(i);
            temp.update(temperature,humidity,pressure);
        }
    }

    /**
     * 通知观察者
     */
    public void measurementsChanged(){
        notifyObserver();
    }

    /**
     * 测试所用手动设置数据,并调用方法
     * @param temperature
     * @param humidity
     * @param pressure
     */
    public void setMeasurements(float temperature,float humidity,float pressure){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }
}

观察者实现---布告栏

package com.yyh.observer;

public class CurrentConditionDisplay implements Observer,DisplayElement {

    private float temperature;
    private float humidity;
    private float pressure;
    //方便观察者注册和删除
    private Subject subject;

    public CurrentConditionDisplay(Subject subject) {
        this.subject = subject;
        //注册当前布告板
        subject.registerObserver(this);
    }

    @Override
    public String toString() {
        return "CurrentConditionDisplay{" +
                "temperature=" + temperature +
                ", humidity=" + humidity +
                ", pressure=" + pressure +
                '}';
    }

    @Override
    public void display() {
        System.out.println(toString());
    }

    @Override
    public void update(float temperature, float humidity, float pressure) {
        //设置参数
        this.humidity = humidity;
        this.pressure = pressure;
        this.temperature = temperature;
        //显示数据
        display();
    }
}

测试类

package com.yyh.observer;

public class TestMain {
    public static void main(String[] args) {
        //创建WeatherData类,主题
        WeatherData weatherData = new WeatherData();
        //创建布告栏
        CurrentConditionDisplay currentConditionDisplay = new CurrentConditionDisplay(weatherData);
        //修改数据
        weatherData.setMeasurements(80,10,80);

        //修改数据
        weatherData.setMeasurements(70,10,80);

        //修改数据
        weatherData.setMeasurements(70,10,80);
    }
}


测试结果
#

从main里面看十分神奇~~~

扩展

在Java里面很多地方会用到观察者模式,我们最熟悉不过的swing里面就有。当我们监听按钮的时候,jbutton对象有一个addActionListener方法。这里就运用到了观察者模式,我们操作的是按钮这个对象,按钮这个对象会通知你创建的这个匿名类进行操作!
并且java里面有两种帮你实现观察者模式的类,一个是java.util.Observable类,另一个是java.util.Observer接口。但是由于篇幅原因这里就不在赘述了。需要注意的是,观察者模式分为推和拉。我们上面实现的就是推。主题主动推送通知,接受者被动接受。另一种是接受者主动获取数据,二者有所不同。


如果你喜欢,那么点个喜欢,谢谢!喜欢是我更新的最大动力!

你可能感兴趣的:(设计模式(二)之观察者模式)