一个demo彻底搞懂观察者模式

一、介绍

观察者模式也被称为发布-订阅(Publish/Subscribe)模式,它属于行为型模式的一种。观察者模式定义了一种一对多的依赖关系,一个主题对象可被多个观察者对象同时监听。当这个主题对象状态变化时,会通知所有观察者对象并作出相应处理逻辑。

二、UML图

一个demo彻底搞懂观察者模式_第1张图片

 

三、入门案例分析 ~ ~ (无使用观察者模式)

上面的内容比较抽象,这里用一个案例加深对观察者模式的理解!

需求:

  • Internet气象站项目:

提供温度、气压和湿度的接口

测量数据更新时需时时通知给第三方 (通知)

需要设计开放型API,便于其他第三方公司也能接入气象站获取数据(订阅)

  • WeatherData类

一个demo彻底搞懂观察者模式_第2张图片

 

  • 通常的设计方案

一个demo彻底搞懂观察者模式_第3张图片

 

1) 定义一个第三方公司的模板类

package com.dgut.edu.cn;

/**
 * 第三方公司的模板类
 */
public class CurrentCondition {
    // 环境温度
    private float temperature;
    // 环境气压
    private float pressure;
    // 环境湿度
    private float humidity;

    /**
     *更新信息
     * @param temperature
     * @param pressure
     * @param humidity
     */
    public void update(float temperature,float pressure,float humidity){
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        display();
    }

    /**
     * 展示数据使用 —— 每个公司的模板不一样
     */
    public void display(){
        System.out.println("***** the day temperature is " + temperature + "******");
        System.out.println("***** the day pressure is " + pressure + "******");
        System.out.println("***** the day humidity is " + humidity + "******");
    }
}

2) 定义气象公司的接口类

package com.dgut.edu.cn;

public class WeatherData {
    // 环境温度
    private float temperature;
    // 环境气压
    private float pressure;
    // 环境湿度
    private float humidity;

    public WeatherData() {
    }

    public float getTemperature() {
        return temperature;
    }

    public void setTemperature(float temperature) {
        this.temperature = temperature;
    }

    public float getPressure() {
        return pressure;
    }

    public void setPressure(float pressure) {
        this.pressure = pressure;
    }

    public float getHumidity() {
        return humidity;
    }

    public void setHumidity(float humidity) {
        this.humidity = humidity;
    }

    // 温度、湿度、气压发生改变时,触发函数
    public void dataChange(){
       
    }
}

3) 因为气象站的接口中,我们需要去调用第三方接口更新数据方法,故引入该第三方公司的实现类,并且在构造方法中进行实例化

在WeatherData中,加入以下代码:

// 别人的接口
private CurrentCondition currentCondition;

public WeatherData(CurrentCondition currentCondition) {
    this.currentCondition = currentCondition;
}

4) 在气象站接口中,写一个跟新数据的方法,模拟气象站自动更新数据


public void setData(float temperature,float pressure,float humidity){
    this.temperature = temperature;
    this.pressure = pressure;
    this.humidity = humidity;
    dataChange();
}

5) 在dataChange方法中去通知第三方接口更新数据

// 温度、湿度、气压发生改变时,触发函数
public void dataChange(){
    currentCondition.update(temperature,pressure,humidity);
}

6)  写测试案例如下:

public class Application {
    public static void main(String[] args) {
        CurrentCondition currentCondition = new CurrentCondition();
        WeatherData weatherData = new WeatherData(currentCondition);
        weatherData.setData(20,50,100);
    }
}

7) 执行结果:

***** the day temperature is 20.0******
***** the day pressure is 50.0******
***** the day humidity is 100.0******
  • 分析上面存在的问题

1)其他第三方公司接入气象站获取数据的问题。

2)无法在运行时动态的添加第三方

【解释:】在上述设计中,在Weather中引入currentCondition的成员变量,那如果有新的第三方模板接入,我们又得创建一个新第三方模板变量,手动去添加更新数据的代码。这样子就很麻烦,在扩展性方面很弱。

 

  • 新的一个解决方案:

根据这种订阅/通知的设计思路,在Weather中提供一个注册服务、移除服务、更改服务的方法,在第三方模板中,定义一个更新数据的接口Observer,在模板类去实现这个接口。而在Weather中,不在存入具体的子类,而是存一个Observer即可,这样就可以完成在不改变WeatherData接口中,动态去添加多个订阅者。

基于以上分析

Subject:登记注册、移除和通知

一个demo彻底搞懂观察者模式_第4张图片

 

Observer:接收输入

一个demo彻底搞懂观察者模式_第5张图片

【总结】到这里就基本能理解观察者模式的UML图,提供注册、移除、更改的接口,以及nodify展示数据的接口

  • 入门案例进一步分析 ~ ~ (观察者模式)

用观察者模式设计重新设计的方案

一个demo彻底搞懂观察者模式_第6张图片

 

1、写observer接口

public interface Observer {
    public void update(float temperature,float pressure,float humidity);
}

2、写Subject接口


public interface Subject {
    public void registerObserver(Observer observer);
    public void removeObserver(Observer observer);
    public void notifyObserver();
}

3、第三方模板类继承该Observer接口

public class CurrentCondition implements Observer {
    // 环境温度
    private float temperature;
    // 环境气压
    private float pressure;
    // 环境湿度
    private float humidity;

    /**
     *更新信息
     * @param temperature
     * @param pressure
     * @param humidity
     */
    public void update(float temperature,float pressure,float humidity){
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        display();
    }

    public void display(){
        System.out.println("***** the day temperature is " + temperature + "******");
        System.out.println("***** the day pressure is " + pressure + "******");
        System.out.println("***** the day humidity is " + humidity + "******");
    }


}
public class ForcastCondition implements Observer{
    // 环境温度
    private float temperature;
    // 环境气压
    private float pressure;
    // 环境湿度
    private float humidity;

    /**
     *更新信息
     * @param temperature
     * @param pressure
     * @param humidity
     */
    public void update(float temperature,float pressure,float humidity){
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        display();
    }

    public void display(){
        System.out.println("***** Tomorrow temperature is " + temperature + "******");
        System.out.println("***** Tomorrow pressure is " + pressure + "******");
        System.out.println("***** Tomorrow humidity is " + humidity + "******");
    }


}


4、Weather类继承该Subject接口

package cn;

import java.util.ArrayList;

public class WeatherDataSt implements Subject{
    // 环境温度
    private float temperature;
    // 环境气压
    private float pressure;
    // 环境湿度
    private float humidity;


    private ArrayList observerArrayList = new ArrayList();

  

    public WeatherDataSt() {
    }

    public float getTemperature() {
        return temperature;
    }

    public void setTemperature(float temperature) {
        this.temperature = temperature;
    }

    public float getPressure() {
        return pressure;
    }

    public void setPressure(float pressure) {
        this.pressure = pressure;
    }

    public float getHumidity() {
        return humidity;
    }

    public void setHumidity(float humidity) {
        this.humidity = humidity;
    }

    // 温度、湿度、气压发生改变时,触发函数
    public void dataChange(){
        notifyObserver();
    }

    public void setData(float temperature,float pressure,float humidity){
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        dataChange();
    }

    @Override
    public void registerObserver(Observer observer) {
        observerArrayList.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        if(observerArrayList.contains(observer))
            observerArrayList.remove(observer);
    }

    @Override
    public void notifyObserver() {
        for (int i = 0 ; i < observerArrayList.size(); i++){
            observerArrayList.get(i).update(temperature,pressure,humidity);
        }
    }
}

5、写测试案例如下

package cn;

public class Application {
    public static void main(String[] args) {
        CurrentCondition currentCondition = new CurrentCondition();
        ForcastCondition forcastCondition =  new ForcastCondition();

        WeatherDataSt weatherData = new WeatherDataSt(currentCondition);


        weatherData.registerObserver(currentCondition);
        weatherData.registerObserver(forcastCondition);
        weatherData.setData(10,480,10);
        System.out.println("========================================");
        weatherData.removeObserver(currentCondition);
        weatherData.setData(20,60,700);
    }
}


6、运行结果

***** the day temperature is 10.0******
***** the day pressure is 480.0******
***** the day humidity is 10.0******
***** Tomorrow temperature is 10.0******
***** Tomorrow pressure is 480.0******
***** Tomorrow humidity is 10.0******
========================================
***** Tomorrow temperature is 20.0******
***** Tomorrow pressure is 60.0******
***** Tomorrow humidity is 700.0******


入门案例最终分析 ~ ~ (观察者模式)— Java自带类至此,我们已经实现了服务的动态订阅和移除。

1、Java内置的观察者

Observable

Observer

2、用Java内置观察者重新设计该项目

3、内置观察者的注意点

Observable是类而不是接口

  1. 代码实例如下:

1、模板类实现OBserver接口

package cn;

import java.util.Observable;
import java.util.Observer;

public class CurrentCondition implements Observer{
    // 环境温度
    private float temperature;
    // 环境气压
    private float pressure;
    // 环境湿度
    private float humidity;


    @Override
    public void update(Observable o, Object arg) {
        this.temperature = ((WeatherData.Data)(arg)).getTemperature();
        this.pressure = ((WeatherData.Data)(arg)).getPressure();
        this.humidity = ((WeatherData.Data)(arg)).getHumidity();
        display();
    }

    public void display(){
        System.out.println("***** the day temperature is " + temperature + "******");
        System.out.println("***** the day pressure is " + pressure + "******");
        System.out.println("***** the day humidity is " + humidity + "******");
    }


}
package cn;

import java.util.Observable;
import java.util.Observer;

public class ForcastCondition implements Observer {
    // 环境温度
    private float temperature;
    // 环境气压
    private float pressure;
    // 环境湿度
    private float humidity;


    @Override
    public void update(Observable o, Object arg) {
        this.temperature = ((WeatherData.Data)(arg)).getTemperature();
        this.pressure = ((WeatherData.Data)(arg)).getPressure();
        this.humidity = ((WeatherData.Data)(arg)).getHumidity();
        display();
    }


    public void display(){
        System.out.println("***** Tomorrow temperature is " + temperature + "******");
        System.out.println("***** Tomorrow pressure is " + pressure + "******");
        System.out.println("***** Tomorrow humidity is " + humidity + "******");
    }


}

2、Weacher继承OBserverable接口

package cn;

import java.util.Observable;

public class WeatherData extends Observable{
    // 环境温度
    private float temperature;
    // 环境气压
    private float pressure;
    // 环境湿度
    private float humidity;


    public WeatherData() {
    }

    public float getTemperature() {
        return temperature;
    }

    public void setTemperature(float temperature) {
        this.temperature = temperature;
    }

    public float getPressure() {
        return pressure;
    }

    public void setPressure(float pressure) {
        this.pressure = pressure;
    }

    public float getHumidity() {
        return humidity;
    }

    public void setHumidity(float humidity) {
        this.humidity = humidity;
    }

    // 温度、湿度、气压发生改变时,触发函数
    public void dataChange(){
        this.setChanged();
       this.notifyObservers(new Data(temperature,pressure,humidity));
    }

    public void setData(float temperature,float pressure,float humidity){
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        dataChange();
    }

    class Data{
        // 环境温度
        private float temperature;
        // 环境气压
        private float pressure;
        // 环境湿度
        private float humidity;


        public Data(float temperature, float pressure, float humidity) {
            this.temperature = temperature;
            this.pressure = pressure;
            this.humidity = humidity;
        }

        public float getTemperature() {
            return temperature;
        }

        public void setTemperature(float temperature) {
            this.temperature = temperature;
        }

        public float getPressure() {
            return pressure;
        }

        public void setPressure(float pressure) {
            this.pressure = pressure;
        }

        public float getHumidity() {
            return humidity;
        }

        public void setHumidity(float humidity) {
            this.humidity = humidity;
        }

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


3、测试代码如下:

package cn;

public class Application {
    public static void main(String[] args) {
        CurrentCondition currentCondition = new CurrentCondition();
        ForcastCondition forcastCondition = new ForcastCondition();

        WeatherData weatherData = new WeatherData();
        weatherData.addObserver(currentCondition);
        weatherData.addObserver(forcastCondition);
        weatherData.setData(111,222,333);
        weatherData.deleteObserver(currentCondition);
        weatherData.setData(1,2,3);
    }
}


4、测试结果如下:

***** Tomorrow temperature is 111.0******
***** Tomorrow pressure is 222.0******
***** Tomorrow humidity is 333.0******
***** the day temperature is 111.0******
***** the day pressure is 222.0******
***** the day humidity is 333.0******
***** Tomorrow temperature is 1.0******
***** Tomorrow pressure is 2.0******
***** Tomorrow humidity is 3.0******


 

 

 

你可能感兴趣的:(23种设计模式)