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


    一、前言

    本文根据《Head first 设计模式》总结。

    二、观察者模式引入

    我们假设有这样的场景:

    公司和某个气象台达成了合作关系,气象台为公司提供数据服务,并且他们打算为我们提供一个WeatherData对象来实现数据服务。他们主要提供的数据服务有实时天气、天气预测、气象分析等。现在我们打算根据他们提供的数据制作几个展板,这几个展板分别用来展示实时天气、天气预测、气象分析。

    公司的程序猿小张得到需求后很快便给出了相应的代码实现:

    public void onDataChange(){
        humidity = getHumidity();
        pressure = getPressure();
        temperature = getTemperature();
        currentInfo.update(temperature,humidity,pressure);
        statisticsInfo.update(temperature,humidity,pressure);
        forecastInfo.update(temperature,humidity,pressure);
    }
    

    需求确实很顺利的实现了,但是很快老板又要求小张添加新的展板用来展示其它的信息。于是小张又开始重复上面的代码。

    很快,小张就厌倦了这种方式,并试图解决程序中的问题。那么,小张的程序中有哪些问题呢?

    1、面向具体实现编程

    所谓面向具体实现编程就是说代码只局限在具体场景中,没有通用性,如果添加新的需求很难去维护。

    2、代码封装性不够

    比如几个对象中都含有update方法,这时就可以考虑抽离出公共接口

    三、认识观察者模式

    在网络不太普及的年代,人们主要通过订阅报纸来获取外部消息。订阅报纸以后我们就无需关注报纸何时更新的相关问题。等到报纸更新以后报社会第一时间通知我们。观察者模式也是同样的道理。

    当观察者注册到被观察者中以后,观察者就无需关注被观察者的最新状态,等都被观察者觉察到变化后就会通知观察者去更新最新的数据。

    3.1 一对多依赖

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

    在这里插入图片描述

    3.2 松耦合

    当两个对象之间松耦合,它们依然可以交互,但是不太清楚彼此的细节。

    对于观察者,主题只知道它实现了某一个接口,但是并不清楚观察者具体的实现细节。无论任何时候,我们都可以向主题中添加或移除一个观察者。因为主题只是依赖一个实现Observer接口的对象列表。无论我们添加或是删除某个观察者都不会影响到主题的运行。而且即使有新的观察者出现,主题也不需要修改任何代码,我们只需要向主题中添加观察者。主题不在乎别的,他只会发送通知给所有实现了观察者接口的对象。

    如果我们在其它地方使用主题或者观察者,可以轻松的复用,因为二者不是紧耦合的。

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

    四、UML类图

    在这里插入图片描述

    五、实现观察者模式

    5.1 接口设计

    主题接口:

    public interface Subject {
        //注册观察者
        void registerObserver(Observer observer);
        //移除观察者
        void removeObserver(Observer observer);
        //通知观察者
        void notifyObservers();
    }
    

    观察者:

    public interface Observer {
        //更新数据
        void update();
    }
    

    公共显示接口:

    public interface DisplayElement {
        void display();
    }
    

    5.2 类设计

    WeatherData.java

    public class WeatherData implements Subject{
        //观察者列表
        private List<Observer> observers;
        private float temperature;
        private float humidity;
        private float pressure;
        private List<Float> forecastTemperatures;
        
        public WeatherData(){
            //初始化观察者列表
            observers = new ArrayList<>();
        }
        public void registerObserver(Observer observer) {
            observers.add(observer);
        }
    
        public void removeObserver(Observer observer) {
            observers.remove(observer);
        }
    
        public void notifyObservers() {
            for (Observer observer : observers) {
                observer.update();
            }
        }
        //当调用这个方法时,会通知所有观察者
        public void measurementsChanged() {
            notifyObservers();
        }
    
        public void setMeasurements(float temperature, float humidity,
                                    float pressure, List<Float> forecastTemperatures) {
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            this.forecastTemperatures = forecastTemperatures;
            measurementsChanged();
        }
    
        public float getTemperature() {
            return temperature;
        }
    
        public float getHumidity() {
            return humidity;
        }
    
        public float getPressure() {
            return pressure;
        }
    
        public List<Float> getForecastTemperatures() {
            return forecastTemperatures;
        }
    
    }
    

    CurrentConditionsDisplay.java

    public class CurrentConditionsDisplay implements Observer, DisplayElement {
    
        private WeatherData weatherData;
        private float temperature;//温度
        private float humidity;//湿度
        private float pressure;//气压
    
        public CurrentConditionsDisplay(WeatherData weatherData) {
            this.weatherData = weatherData;
            //注册观察者
            this.weatherData.registerObserver(this);
        }
    
        @Override
        public void display() {
            System.out.println("当前温度为:" + this.temperature + "℃");
            System.out.println("当前湿度为:" + this.humidity);
            System.out.println("当前气压为:" + this.pressure);
        }
    
        @Override
        public void update() {
            this.temperature = this.weatherData.getTemperature();
            this.humidity = this.weatherData.getHumidity();
            this.pressure = this.weatherData.getPressure();
            display();
        }
    }
    

    5.3 测试

    public class ObserverPatternTest {
        public static void main(String[] args) {
            WeatherData weatherData = new WeatherData();
            new CurrentConditionsDisplay(weatherData);
            weatherData.setMeasurements(22f, 0.8f, 1.2f, null);
        }
    }
    
  • 相关阅读:
    程序猿之没事瞎吐槽
    iOS 打印日志的保存 (一)
    Xcode4.5 本地化,多语言设置
    css3渐变画斜线 demo
    关于JavaScript的一些记录
    Windows 10 自带输入法(微软拼音)繁体简体切换快捷键
    ng-class用法小记
    基于vue监听滚动事件,实现锚点链接平滑滚动
    总结继承的几种方式
    浅谈jQuery的内部框架结构,操作
  • 原文地址:https://www.cnblogs.com/zwscode/p/14284082.html
Copyright © 2020-2023  润新知