设计模式之观察者模式

目录

 

观察者模式介绍

气象站

最初的气象应用

布告板接口

布告板实现

气象台监控

测试

布告板发展

气象站观察者模式

测试

Java内置实现观察者

WeatherData

Display

CurrentDisplay

Current2Display

Test

输出结果


观察者模式介绍

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

 

气象站

下面通过气象站的事例来介绍观察者模式

最初的气象应用

最开始气象站有三个感应装置,分别为温度(temperature)、湿度(humidity)和气压(pressure),显示装置也就只有一个布告板(具体如下),气象站的三个感应装置获取到的最新数据后要展示在布告板上,因此我们可能设计如下的实现:

当前天气情况:
气温:25℃
湿度:60
气压:1atm

布告板接口

public interface Display {
    void display (double temperature, double humidity, double pressure);
}

布告板实现

public class CurrentDisplay implements Display {
    public void display (double temperature, double humidity, double pressure) {
        String content = String.format("当前天气情况:\n气温:%s℃\n湿度:%s\n气压:%satm", temperature, humidity, pressure);
        System.out.println(content);
    }
}

气象台监控

public class WeatherData {
    private double temperature;
    private double humidity;
    private double pressure;

    public void weatherDataChange(double temperature, double humidity, double pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        updateDisplay();
    }

    private void updateDisplay() {
        new CurrentDisplay().display(temperature, humidity, pressure);
    }
}

测试

public class Test {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        weatherData.weatherDataChange(25D, 72D, 1.1D);
    }
}

输出结果

当前天气情况:
气温:25.0℃
湿度:72.0
气压:1.1atm

布告板发展

随着业务的发展,布告板的展现形式也越来越多种多样,按照上述的形式,我们只能在WeatherData:updateDisplay()下面不断的新增需要通知的布告板,这个看起来没有什么问题,但是细想下每次新增一个布告板,我们都需要在WeatherData:updateDisplay()下面新加一个通知,没移除一个布告板,都需要将WeatherData:updateDisplay()下面对应的进行移除,天气数据和布告板紧紧的耦合在一起,这个并不符合我们的高内聚低耦合的设计原则,因此我们需要再次进行优化,设计为观察者模式。

 

气象站观察者模式

针对上述,布告板我们无需进行改变,我们对WeatherData进行优化,具体如下(这里我们只介绍设计模式,不考虑线程安全):

public class WeatherData {
    private double temperature;
    private double humidity;
    private double pressure;

    private List<Display> displays = new ArrayList<Display>();

    //注册观察者
    public void addDisplay(Display display) {
        displays.add(display);
    }

    //取消注册
    public void removeDisplay(Display display) {
        int i = displays.indexOf(display);
        if (i >= 0) {
            displays.remove(display);
        }
    }

    public void weatherDataChange(double temperature, double humidity, double pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        updateDisplay();
    }

    private void updateDisplay() {
        for (Display display : displays) {
            display.display(temperature, humidity, pressure);
        }
    }
}

测试

public class Test {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        Display display1 = new CurrentDisplay();
        Display display2 = new Current2Display();
        Display display3 = new CurrentDisplay();
        weatherData.addDisplay(display1);
        weatherData.addDisplay(display2);
        weatherData.addDisplay(display3);
        System.out.println("----------注册三个观察者----------");
        weatherData.weatherDataChange(25D, 72D, 1.1D);
        weatherData.removeDisplay(display3);
        System.out.println("----------取消第三个观察者----------");
        weatherData.weatherDataChange(28D, 77D, 0.9D);
    }
}

输出结果

----------注册三个观察者----------
当前天气情况:
气温:25.0℃
湿度:72.0
气压:1.1atm
当前天气情况2:
气温:25.0℃
湿度:72.0
气压:1.1atm
当前天气情况:
气温:25.0℃
湿度:72.0
气压:1.1atm
----------取消第三个观察者----------
当前天气情况:
气温:28.0℃
湿度:77.0
气压:0.9atm
当前天气情况2:
气温:28.0℃
湿度:77.0
气压:0.9atm

这样我们就把布告板从气象台中抽象出来,后续再添加布告板,我们也无需再次修改WeatherData代码。

 

Java内置实现观察者

Java内置中提供了 java.util.Observer接口和java.util.Observable类来实现观察者模式,下面我们就使用Java内置工具来实现上述气象台的观察者模式。

WeatherData

package com.lulei.study.design.patterns.observer;

import lombok.Data;

import java.util.Observable;

/**
 * Created by lulei on 2019/4/16.
 */
@Data
public class WeatherData extends Observable{
    private double temperature;
    private double humidity;
    private double pressure;


    public void weatherDataChange(double temperature, double humidity, double pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        updateDisplay();
    }

    private void updateDisplay() {
        //在调用notifyObservers()之前,先调用setChanged()来指示状态已经改变
        setChanged();
        //这里我们没有传送数据,表示我们采用的做法是拉
        notifyObservers();
    }
}

Display

package com.lulei.study.design.patterns.observer;

/**
 * Created by lulei on 2019/4/16.
 */
public interface Display {
    void display (double temperature, double humidity, double pressure);
}

 

CurrentDisplay

package com.lulei.study.design.patterns.observer;

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

/**
 * Created by lulei on 2019/4/16.
 */
public class CurrentDisplay implements Observer, Display {
    public CurrentDisplay(Observable observable) {
        observable.addObserver(this);
    }

    public void display (double temperature, double humidity, double pressure) {
        String content = String.format("当前天气情况:\n气温:%s℃\n湿度:%s\n气压:%satm", temperature, humidity, pressure);
        System.out.println(content);
    }

    public void update(Observable observable, Object arg) {
        if (observable instanceof WeatherData) {
            WeatherData weatherData = (WeatherData)observable;
            display(weatherData.getTemperature(), weatherData.getHumidity(), weatherData.getPressure());
        }
    }
}

Current2Display

package com.lulei.study.design.patterns.observer;

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

/**
 * Created by lulei on 2019/4/16.
 */
public class Current2Display implements Observer, Display {
    public Current2Display(Observable observable) {
        observable.addObserver(this);
    }

    public void display (double temperature, double humidity, double pressure) {
        String content = String.format("当前天气情况2:\n气温:%s℃\n湿度:%s\n气压:%satm", temperature, humidity, pressure);
        System.out.println(content);
    }

    public void update(Observable observable, Object arg) {
        if (observable instanceof WeatherData) {
            WeatherData weatherData = (WeatherData)observable;
            display(weatherData.getTemperature(), weatherData.getHumidity(), weatherData.getPressure());
        }
    }
}

 

Test

package com.lulei.study.design.patterns.observer;

import java.util.Observer;

/**
 * Created by lulei on 2019/4/16.
 */
public class Test {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        Observer display1 = new CurrentDisplay(weatherData);
        Observer display2 = new Current2Display(weatherData);
        Observer display3 = new CurrentDisplay(weatherData);
        System.out.println("----------注册三个观察者----------");
        weatherData.weatherDataChange(25D, 72D, 1.1D);
        weatherData.deleteObserver(display3);
        System.out.println("----------取消第三个观察者----------");
        weatherData.weatherDataChange(28D, 77D, 0.9D);
    }
}

 

输出结果

----------注册三个观察者----------
当前天气情况:
气温:25.0℃
湿度:72.0
气压:1.1atm
当前天气情况2:
气温:25.0℃
湿度:72.0
气压:1.1atm
当前天气情况:
气温:25.0℃
湿度:72.0
气压:1.1atm
----------取消第三个观察者----------
当前天气情况2:
气温:28.0℃
湿度:77.0
气压:0.9atm
当前天气情况:
气温:28.0℃
湿度:77.0
气压:0.9atm

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
上篇:软件设计模式例子代码  【例2.2】简单工厂方法模式-汽车保险  【例2.3】工厂方法模式-汽车保险  【例2.4】抽象工厂模式-房屋信息  【例2.5】生成器模式-房屋信息  【例2.6】单例模式-互联网连接  【例3.2】组合模式-五子棋代码  【例3.3】组合模式-空军指挥系统  【例3.4】组合模式-世界问候语  【例3.7】类适配器模式-客户信息验证  【例3.8】对象适配器模式-字符串排序  【例3.10】外观模式-安全系统  【例3.11】外观模式-椭圆功能  【例3.13】桥接模式-茶水机系统  【例3.14】桥接模式-几何立体体积  【例4.1】迭代器模式-矩阵搜索  【例4.2】迭代器模式-产品搜索  【例4.4】访问者模式-名牌鞋销售软件  【例4.5】访问者模式-计算机部件销售软件  【例4.6】命令模式-室内温度控制  【例4.7】命令模式-室内温度控制-2个GUI  【例4.8】命令模式-室内温度控制-3个GUI  【例4.10】中介者模式-旅游信息共享  【例4.11】中介者模式-海岛机场  【例4.13】策略模式-整数排序  【例4.14】策略模式-中国属相  【例4.16】状态模式-交通信号灯-设计1  【例4.16】状态模式-交通灯信号灯-设计2  【例4.16】状态模式-交通灯信号灯-设计3 下篇:软件体系结构例子代码  【例6.4】结构化设计-文件更新-C源代码  【例6.5】面向对象设计架构-文件更新  【例6.7】顺序批处理架构-文件更新  【例6.8】顺序批处理架构-图像处理  【例6.9】管道过滤器架构-主动过滤器  【例6.10】管道过滤器架构-被动过滤器  【例6.11】管道-过滤器架构-文件更新  【例6.12】管道-过滤器架构-图像处理程  【例6.14】事件体系结构-鼠标响应  【例6.17】事件体系结构-观察者模式-大草原1  【例6.18】事件体系结构-观察者模式-大草原2  【例6.19】事件体系结构-观察者模式-温度显示  【例6.21】层次架构-软件测试  【例6.22】层次架构-银行- Access数据库  【例6.23】MVC架构-二手车拍卖-无观察者  【例6.24】MVC架构-二手车拍卖-观察者-3个图形界面  【例6.25】MVC架构-二手车拍卖-观察者-1个图形界面

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值