zoukankan      html  css  js  c++  java
  • 观察者模式的理解和使用

    一、是什么?作用

    1. 观察者模式定义了一系列对象之间的一对多关系

    2. 当一个对象改变状态, 其他依赖着都会受到通知

    二、示例

    需求: 气象观测天气,并定时更新观测数据,我们的电子仪器需要接受这些数据

    1. PUSH模式, 由被观察者推送给观察者

    1. 定义主题, 即被观察者

    /**
     * 主题
     */
    public interface Subject {
    
        // 添加观察者
        void registerObserver(Observer o);
    
        // 删除观察者
        void removeObserver(Observer o);
    
        // 通知
        void notifyObservers();
    }

    2. 定义观察者的超类,里面只有一个更新的方法

    /**
     * 观察者超类
     */
    public interface Observer {
    
        public void update(float temp, float humidity, float pressure);
    }

    3. 天气数据, 主题的子类

      1. 有一个属性来存放观察者

      2. 实现主题的方法

      3. 有三个数据需要传递(温度、湿度、气压)

     1 /**
     2  * 天气数据, 实现主题
     3  */
     4 public class WeatherData implements Subject {
     5 
     6     /**
     7      * 存储观察者
     8      */
     9     private List<Observer> observers;
    10     private float temperature;
    11     private float humidity;
    12     private float pressure;
    13 
    14     public WeatherData() {
    15         this.observers = new ArrayList<>();
    16     }
    17 
    18     /**
    19      * 当气象站得到更新观测值时,我们通知观察者
    20      */
    21     public void measurementsChanged() {
    22         notifyObservers();
    23     }
    24 
    25     /**
    26      * 模拟气象站更改了气象数据
    27      */
    28     public void setMeasurements(float temperature, float humidity, float pressure) {
    29         // 更改气象数据
    30         this.temperature = temperature;
    31         this.humidity = humidity;
    32         this.pressure = pressure;
    33 
    34         // 通知观察者
    35         measurementsChanged();
    36     }
    37 
    38     @Override
    39     public void registerObserver(Observer o) {
    40         observers.add(o);
    41     }
    42 
    43     @Override
    44     public void removeObserver(Observer o) {
    45         int i = observers.indexOf(0);
    46         if (i >= 0) {
    47             observers.remove(0);
    48         }
    49     }
    50 
    51     @Override
    52     public void notifyObservers() {
    53         for (Observer observer : observers) {
    54             observer.update(temperature, humidity, pressure);
    55         }
    56     }
    57 
    58     public float getTemperature() {
    59         return temperature;
    60     }
    61 
    62     public float getHumidity() {
    63         return humidity;
    64     }
    65 
    66     public float getPressure() {
    67         return pressure;
    68     }
    69 }

    4. 观察者具体类, 实现观察者,将主题通过构造传入,并订阅(这里将耦合度降到了很低了),实现更新方法

    /**
     * 显示当前天气的仪器 - 观察者的具体类
     */
    public class NowConditionDisplay implements Observer {
        private float temperature;
        private float humidity;
        private WeatherData weatherData;
    
        public NowConditionDisplay(WeatherData weatherData) {
            this.weatherData = weatherData;
            weatherData.registerObserver(this);
        }
    
        @Override
        public void update(float temp, float humidity, float pressure) {
            this.temperature = temp;
            this.humidity = humidity;
            display();
        }
    
        public void display() {
            System.out.println("[push] 当前温度:" + temperature + " 当前湿度: " + humidity);
        }
    }

    测试

    public class pushMain {
    
        public static void main(String[] args) {
            WeatherData weatherData = new WeatherData();
            NowConditionDisplay nowConditionDisplay = new NowConditionDisplay(weatherData);
    
            weatherData.setMeasurements(20, 10, 29.2f);
        }
    }
    
    
    控制台显示:
    [push] 当前温度:20.0 当前湿度: 10.0

    2. PULL模式, 由观察者去拉数据

    1. 天气数据提供者,利用java.util包下的Observable类来实现

    import java.util.Observable;
    
    /**
     * 数据提供者
     */
    public class WeatherData extends Observable {
    
        // 三个数据
        private float temperature;
        private float humidity;
        private float pressure;
    
        public WeatherData() {
        }
    
        public void measurementChanged() {
            setChanged();
            notifyObservers();
        }
    
        public void setMeasurements(float temperature, float humidity, float pressure) {
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
    
            measurementChanged();
        }
    
        public float getTemperature() {
            return temperature;
        }
    
        public float getHumidity() {
            return humidity;
        }
    
        public float getPressure() {
            return pressure;
        }
    }

    2. 观察者子类, 实现java.util的Observer 

    import java.util.Observable;
    import java.util.Observer;
    
    /**
     * @author wb-xp570304 on 2019/7/9
     */
    public class NowConditionDisplay implements Observer {
    
        Observable observable;
        private float temperature;
        private float humidity;
    
        public NowConditionDisplay(Observable observable) {
            this.observable = observable;
            observable.addObserver(this);
        }
    
        @Override
        public void update(Observable o, Object arg) {
            if (o instanceof WeatherData) {
                WeatherData weatherData = (WeatherData) o;
                this.temperature = weatherData.getTemperature();
                this.humidity = weatherData.getHumidity();
                display();
            }
        }
    
        public void display() {
            System.out.println("当前温度: " + temperature + " 湿度: " + humidity);
        }
    }

    测试:

    public class pullMain {
    
        public static void main(String[] args) {
            WeatherData weatherData = new WeatherData();
    
            NowConditionDisplay nowConditionDisplay = new NowConditionDisplay(weatherData);
    
            weatherData.setMeasurements(80, 65, 30f);
        }
    }

    控制台显示:
      当前温度: 80.0 湿度: 65.0

    小结: 

      第二种pull的方式这里是利用java.util.Observable来实现的,而且用的是继承,减少了代码的可扩展性

    三、总结

     1. 观察者模式的理念是,为交互对象之间的松耦合设计而努力

  • 相关阅读:
    如何获得浏览器localStorage的剩余容量
    按Enter键后Form表单自动提交的问题
    IE10 11的css hack
    text-transform设置单词首字母大写
    Jade模板引擎(一)之Attributes
    sql server之ROW_NUMBER() OVER()取每组的第N行数据
    CSS3之让背景图片全部显示
    摆脱npm的网络问题: 淘宝npm镜像
    MaskedTextBox的聚焦和光标位置
    将博客搬至CSDN
  • 原文地址:https://www.cnblogs.com/milicool/p/11189629.html
Copyright © 2011-2022 走看看