zoukankan      html  css  js  c++  java
  • [head first 设计模式]第二章 观察者模式

    [head first 设计模式]第二章 观察者模式

    假如我们有一个开发需求——建造一个气象观测站展示系统。需求方给我们提供了一个WeatherObject对象,能够自动获得最新的测量数据。而我们要建立一个应用,有三种布告版,分别显示目前的状况,气象统计,简单预报。三种布告板能即时显示WeatherObject对象中更新的数据。

    ​同时,我们需要这是一个可扩展的气象站,可以公布一组api,好让其他开发人员写出自己的布告板插入此应用中。

    ​我们首先来看看我们的大致系统框架

    1.jpg

    我们的工作就算建立一个应用,利用weatherData对象取得数据,并更新布告板。

    根据weatherData源文件,我们的工作是实现measurementChanged(),当测量数据备妥时,measurementChanged()方法将会被调用。

    2.jpg

    先来看一个可能的实现,

    3.jpg

    很明显,这个实现并不妥当。回想第一章的OO原则,会发现我们在针对具体实现编程,这会导致当有新需求时我们必须修改程序。同时,更新布告板的代码会经常改变,我们应该尽可能将其封装。

    接下来我们将应用观察者模式来改进现有设计。

    以报纸订阅为例,我们像某家报社订阅报纸,只要他们有新报纸初版,就会给派送给订户。而订户不想要了,就可以取消订阅。只要报社还在运营,就不断有人订阅或者取消订阅报纸。

    出版者+订阅者=观察者模式

    如果了解了报纸订阅是怎么回事,观察者模式也大体如此。出版者即为观察者模式中的主题(Subject),订阅者即为观察者模式中的观察者(Observer)

    4.jpg

    定义观察者模式

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

    类图如图所示

    5.jpg

    观察者模式提供了一种对象设计,让主题和观察者之间松耦合。

    对于观察者,主题只关心观察者实现了Observer接口,主题并不关心观察者的细节。

    任何时候都可以新增观察者,因为主题唯一以来的东西是一个实现了Observer接口的对象列表,同时,也可以在任何时候删除观察者。

    改变主题或观察者中的其中一方,并不会影响到另一方。

    设计原则

    设计应该尽可能降低交互对象之间的耦合度

    依照观察者模式,得到我们的新设计

    6.jpg

    当前,我们暂时不用Java内置的观察者模式,而是自己实现这部分代码。

    public interface Observer {
        public void update(float temp,float humidity,float pressure);
    }
    
    
    public interface Subject {
        public void notifyObserver();
        public void removeObserver(Observer observer);
        public void registerObserver(Observer observer);
    
    }
    
    public interface DisplayElement {
        public void display();
    }
    
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class WeatherData implements Subject {
        private List<Observer> Observers;
        private float temperature;
        private float humidity;
        private float pressure;
        public WeatherData()
        {
            Observers = new ArrayList<Observer>();
        }
    
        @Override
        public void notifyObserver() {
            for (Observer o:
                Observers ) {
                o.update(temperature,humidity,pressure);
            }
        }
    
        @Override
        public void removeObserver(Observer observer) {
            Observers.remove(observer);
        }
    
        @Override
        public void registerObserver(Observer observer) {
            Observers.add(observer);
        }
    
        public void measurementChanged()
        {
            notifyObserver();
        }
    
        public void setMeasurements(float temperature,float humidity,float pressure)
        {
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            measurementChanged();
        }
    }
    
    
    public class CurrentConditionsDisplay implements Observer,DisplayElement{
        private float temperature;
        private float humidity;
        private Subject weatherData;
        @Override
        public void display() {
            System.out.println("Current conditions: "+temperature+"F degrees and "+humidity+"% humidity");
        }
    
        @Override
        public void update(float temp, float humidity, float pressure) {
        this.temperature = temp;
        this.humidity = humidity;
        display();
        }
    
        public CurrentConditionsDisplay( Subject weatherData) {
            this.weatherData = weatherData;
            weatherData.registerObserver(this);
        }
    
    
    }
    
    public class WeatherStation {
        public static void main(String[] args) {
            WeatherData weatherData = new WeatherData();
            CurrentConditionsDisplay currentConditionsDisplay =
                    new CurrentConditionsDisplay(weatherData);
            weatherData.setMeasurements(80,65,30.4f);
        }
    }
    
    

    使用Java内置的观察者模式

    Java api有自带的观察者模式,包含Observer接口和Observable类,在使用上更加方便,很多功能已经事先准备好了。如下是我们使用Java内置观察者模式修改后的设计。

    7.jpg

    注册/删除观察者

    调用Observable对象的addObserver方法和deleteObserver方法即可

    被观察者送出通知

    首先调用setChanged()方法,标记状态已经改变,后调用notifyObservers(),那么所有观察者都会调用自身的update方法。

    import java.util.Observable;
    import java.util.Observer;
    
    public class CurrentConditionsDisplay implements Observer,DisplayElement{
        private double temperature;
        private double humidity;
        private Observable observable;
        @Override
        public void display() {
            System.out.println("Current temperature "+temperature+"F degrees and "+humidity+"%humidity");
        }
    
        public CurrentConditionsDisplay(Observable observable)
        {
            this.observable = observable;
            observable.addObserver(this);
        }
    
        @Override
        public void update(Observable o, Object arg) {
            if(o instanceof WheatherData)
            {
    
                temperature = ((WheatherData) o).getTemperature();
                humidity = ((WheatherData) o).getHumidity();
                display();
            }
        }
    }
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Observable;
    
    public class WheatherData extends Observable {
        private double temperature;
        private double humidity;
        private double pressure;
        public double getHumidity() {
            return humidity;
        }
    
        public double getPressure() {
            return pressure;
        }
    
        public double getTemperature()
        {
            return temperature;
        }
        
        public void setMeasurements(double temperature,double humidity,double pressure)
        {
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            setChanged();
            notifyObservers();
        }
    }
    
    

    不幸的是,observable是一个类而不是接口,导致我们难以继承其他类,同时也无法拥有自己独特的实现。

    在实际使用时,我们需要权衡是使用jdk自带的观察者模式亦或是由自己实现。

  • 相关阅读:
    组合与计数
    20160929训练记录
    奇特而有用的定理
    图论 500 题
    《长安十二时辰》愿你看尽世间百态,心中仍有热血
    洛谷 [P1337] 平衡点
    洛谷 [P3496] BLO
    洛谷 [P2341] 受欢迎的牛
    洛谷 [P3723] 礼物
    洛谷 [P3338] 力
  • 原文地址:https://www.cnblogs.com/alex101/p/14027901.html
Copyright © 2011-2022 走看看