美文网首页
Head First设计模式学习笔记一观察者模式

Head First设计模式学习笔记一观察者模式

作者: 巾二 | 来源:发表于2018-09-04 07:30 被阅读0次

    假设我们现在要建设一个气象站,由WeatherData对象负责追踪目前的天气状况(温度、湿度、气压)。现在有三种布告板,分别显示目前的状况、气象统计及简单的预报。当WeatherData对象获得最新的测量数据时,三种布告板必须实时更新。并且可以随时添加其他类型的布告板。
    如下,WeatherData对象包含四个方法

    public class WeatherData {
        private float temperature;
        
        private float humidity;
        
        private float pressure;
    
        //获取温度
        public float getTemperature() {
            return temperature;
        }
    
        //获取湿度
        public float getHumidity() {
            return humidity;
        }
    
        //获取气压
        public float getPressure() {
            return pressure;
        }
        
        //一但气象测量更新,此方法会被调用
        public void mentsChanged() {
            //......
        }
    }
    

    假设现在三个布告板分别为下

    //目前状况
    public class CurrentConditionDisplay {
    
        public void update(float temperature, float humidity, float pressure){
            System.out.println("CurrentConditionDisplay");
        }
    }
    
    //气象统计
    public class StatisticsDisplay {
    
        public void update(float temperature, float humidity, float pressure){
            System.out.println("StatisticsDisplay");
        }
    }
    
    //简单预报
    public class ForecastDisplay {
    
        public void update(float temperature, float humidity, float pressure){
            System.out.println("ForecastDisplay");
        }
    }
    

    下面我们在WeatherData中调用布告板的update()方法

    public class WeatherData {
        //实例变量声明
        
        //一但气象测量更新,此方法会被调用
        public void mentsChanged() {
            float temperature = getTemperature();
            float humidity = getHumidity();
            float pressure = getPressure();
            
            currentConditionDisplay.update(temperature, humidity, pressure);
            statisticsDisplay.update(temperature, humidity, pressure);
            forecastDisplay.update(temperature, humidity, pressure);
        }
    }
    
    

    我们看上面的调用虽然能实现WeatherData的数据每次更新的时候通知各个布告板更新数据。但是在每次增加或修改布告板的时候,都需要去修改程序。所以这并不是一个好的解决方法。

    下面我们看看如果使用观察者模式会怎么做。

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

    比如我们向报社订阅报纸,只要我们订阅了,报社有新报纸了就给我们送过来。当我们取消订阅的时候,报社就不再给我们送报纸了。那么观察者模式其实就跟报纸订阅很类似,出版社就是观察者模式中的“主题”(Subject),订阅者就是“观察者”(Observer)

    观察者模式有一个主题接口

    public interface Subject {
        //将观察者注册到主题中
        void registerObserver(Observer observer);
        //将观察者从主题中移除
        void removeObserver(Observer observer);
        //在状态改变时更新所有当前观察者
        void notifyObservers();
    }
    

    每个主题有多个观察者,观察者接口如下

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

    观察者模式中每个观察者必须注册具体主题,以便接受更新。
    还有一个布告板接口,当布告板需要显示的时候,调用dispaly()接口。

    public interface DisplayElement {
        void display();
    }
    

    再在WeatherData类中实现Subject接口

    public class WeatherData implements Subject {
        private List<Observer> observers;
    
        private float temperature;
    
        private float humidity;
    
        private float pressure;
    
        public WeatherData() {
            observers = new ArrayList<Observer>();
        }
    
        public void registerObserver(Observer observer) {
            observers.add(observer);
        }
    
        public void removeObserver(Observer observer) {
            int i = observers.indexOf(observer);
            if (i >= 0){
                observers.remove(i);
            }
        }
    
        public void notifyObservers() {
            for (Observer observer : observers){
                observer.update(temperature, humidity, pressure);
            }
        }
        
        //当气象站得到更新观测值时,我们通知观察者
        public void measurementsChanged() {
            notifyObservers();
        }
        
        public void setMeasurements(float temperature, float humidity, float pressure){
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            measurementsChanged();
        }
    }
    

    再来看看布告板的具体实现

    public class CurrentConditionsDisplay implements Observer, DisplayElement {
        private float temperature;
    
        private float humidity;
    
        private float pressure;
    
        private Subject weatherData;
    
        public CurrentConditionsDisplay(Subject weatherData) {
            this.weatherData = weatherData;
            //将观察者注册到主题上面
            weatherData.registerObserver(this);
        }
    
        public void update(float temperature, float humidity, float pressure) {
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            display();
        }
    
        public void display() {
            System.out.println("CurrentConditionsDisplay");
            System.out.println("temperature:"+temperature+", humidity:"+humidity+", pressure:"+pressure);
        }
    }
    

    省略其他两个布告板的实现。
    再写一个WeatherStation的类运行气象站

    public class WeatherStation {
        public static void main(String[] args) {
            WeatherData weatherData = new WeatherData();
    
            CurrentConditionsDisplay currentConditionDisplay = new CurrentConditionsDisplay(weatherData);
            StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
            ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
    
            weatherData.setMeasurements(10, 20, 30);
            weatherData.setMeasurements(100, 200, 300);
        }
    }
    
    输出:
    CurrentConditionsDisplay
    temperature:10.0, humidity:20.0, pressure:30.0
    StatisticsDisplay
    temperature:10.0, humidity:20.0, pressure:30.0
    ForecastDisplay
    temperature:10.0, humidity:20.0, pressure:30.0
    CurrentConditionsDisplay
    temperature:100.0, humidity:200.0, pressure:300.0
    StatisticsDisplay
    temperature:100.0, humidity:200.0, pressure:300.0
    ForecastDisplay
    temperature:100.0, humidity:200.0, pressure:300.0
    

    我们能看到,观察者模式中,主题和观察者是松耦合的。改变主题或观察者其中的一方,并不会影响另一方。任何时候我们都可以增加新的观察者,因为主题唯一依赖的东西是一个实现Observer接口的对象列表。

    当有新类型的观察者出现时,主题的代码也不需要修改。而且我们还可以独立的复用主题或观察者。

    松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的相互依赖降到了最低。
    为了交互对象之间的松耦合设计而努力

    相关文章

      网友评论

          本文标题:Head First设计模式学习笔记一观察者模式

          本文链接:https://www.haomeiwen.com/subject/ecbwwftx.html