zoukankan      html  css  js  c++  java
  • 设计模式(十九)观察者模式 Observer

    • 模拟场景:

      甲方提供了一个气象站的接口,气象站上面装有:温度感应装置、湿度感应装置、气压感应装置。

      现在我们是乙方,需要设计一个 WeatherData 对象,从气象站获取数据,并且利用这些数据,更新三个布告板(当前状况、气象统计、天气预报)。

    • 第一版解决方案:

      通过简单地分析,我们可以很快确定一套解决方案:

      WeatherData 提供一个 measurementsChanged() 方法,当这个方法被调用了,去实时获取气象站的数据,然后更新到三个布告板上。

    public class BadWeatherData {
    
        @Getter
        private float temperature;
        @Getter
        private float humidity;
        @Getter
        private float pressure;
    
        private CurrentConditionsDisplay currentConditionDisplay;
        private StatisticsDisplay statisticsDisplay;
        private ForecastDisplay forecastDisplay;
    
        public BadWeatherData() {
            // some initialized function for displays
        }
    
        // We don't care how it be called, we only know is when it is called, we will update displays.
        public void measurementsChanged() {
            // We don't care how it gets data
            float temperature = getTemperature();
            float humidity = getHumidity();
            float pressure = getPressure();
    
            currentConditionDisplay.update(temperature, humidity, pressure);
            statisticsDisplay.update(temperature, humidity, pressure);
            forecastDisplay.update(temperature, humidity, pressure);
        }
    }
    • 第一套方案有什么问题?

      显然,这是一个扩展性很差的解决方案,它有如下问题:

    1. 没有针对接口编程。(Display 应该事先一个公共的接口)
    2. 如果需要增加或者删除 Display,都要修改代码。
    3. 不能动态地增加或者删除 Display。
    • 观察者模式:

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

      观察者模式 = 主题+观察者(Subject + Observer)。

    • 理想的 WeatherData 设计方案:
    1. Display 对象,作为观察者,需要实现统一的 Observer 接口。
    2. Observer 接口,具有更新 temperature, humidity, pressure 的能力。
    3. WeatherData 对象,作为主题,需要实现 Subject 接口。
    4. Subject 接口,维护一个 Oberver 列表,对外提供将 Observer 加入/移除 列表的接口,并且具有通知所有 Observer 数据变化的能力。
    5. Observer 可以主动 订阅/取消 Subject。

      

    • UML 类图(为了防止混乱,类图只显示一个 Display 对象):

    • 第二版解决方案:
    public interface Subject {
    
        void registerObserver(Observer observer);
        void removeObserver(Observer observer);
        void notifyObservers();
    }
    public interface Observer {
    
        void update(float temperature, float humidity, float pressure);
    }
    public interface DisplayElement {
    
        void display();
    }
    @Data
    public final class WeatherData implements Subject {
    
        private float temperature;
        private float humidity;
        private float pressure;
    
        private List<Observer> observers = new ArrayList<>();
    
        public void measurementsChanged() {
            notifyObservers();
        }
    
        @Override
        public void registerObserver(Observer observer) {
            observers.add(observer);
        }
    
        @Override
        public void removeObserver(Observer observer) {
            observers.remove(observer);
        }
    
        @Override
        public void notifyObservers() {
            observers.forEach(observer -> observer.update(temperature, humidity, pressure));
        }
    }
    public class CurrentConditionsDisplay implements Observer, DisplayElement {
    
        private float temperature;
        private float humidity;
    
        private Subject weatherData;
    
        public CurrentConditionsDisplay(Subject weatherData) {
            this.weatherData = weatherData;
            weatherData.registerObserver(this);
        }
    
        @Override
        public void display() {
            System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
        }
    
        @Override
        public void update(float temperature, float humidity, float pressure) {
            this.temperature = temperature;
            this.humidity = humidity;
            display();
        }
    }
    public class ForecastDisplay implements Observer, DisplayElement {
    
        private float temperature;
        private float humidity;
        private float pressure;
    
        private Subject weatherData;
    
        public ForecastDisplay(Subject weatherData) {
            this.weatherData = weatherData;
            weatherData.registerObserver(this);
        }
    
        @Override
        public void display() {
            System.out.println("Will show forecast related data");
        }
    
        @Override
        public void update(float temperature, float humidity, float pressure) {
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            display();
        }
    }
    public class StatisticsDisplay implements Observer, DisplayElement {
    
        private float temperature;
    
        private Subject weatherData;
    
        public StatisticsDisplay(Subject weatherData) {
            this.weatherData = weatherData;
            weatherData.registerObserver(this);
        }
    
        @Override
        public void display() {
            System.out.println("Statistics will show average temperature");
        }
    
        @Override
        public void update(float temperature, float humidity, float pressure) {
            this.temperature = temperature;
            display();
        }
    }
  • 相关阅读:
    关于Java的i++和++i的区别
    Java基础(八 前面补充)
    Java基础(七)
    Java基础(六)
    Java基础(五)
    Java基础(四)
    Java基础(三)
    Java基础(二)
    Java基础
    阿里技术专员《并发编程技术分享》
  • 原文地址:https://www.cnblogs.com/jing-an-feng-shao/p/10968609.html
Copyright © 2011-2022 走看看