美文网首页
设计模式(二)观察者模式

设计模式(二)观察者模式

作者: Misout | 来源:发表于2018-04-01 09:00 被阅读73次

    1.前言

    本期分享设计模式主题:观察者设计模式。

    这是一个非常简单易学的设计模式,读完本文,你能知道观察者模式的设计以及设计思想。

    2.模式简介

    这是一个可以帮助你的对象知悉现状,不会错过对该对象感兴趣的事。对象甚至在运行时可决定是否需要继续被通知。观察者模式也是JDK中使用最多的模式之一,非常有用。

    3.模式定义

    观察者模式是在对象之间,定义一对多的依赖关系。基于这样的关系,如果对象发生状态变化,与之依赖的多个对象(监听的对象)能够收到状态变化通知,并进行更新。是一个以松耦合的方式,让一个对象与一系列对象进行协作沟通的方式。

    观察者模式有两种方式的实现,一种是推(push),另一种是主动拉(pull),推和拉都是针对通知而言。本着介绍推模式。

    4.模式UML类图

    观察者模式的UML类图如下图:


    观察者模式UML类图

    角色划分

    • Subject:主题或中心对象,一对多中的一,接口或抽象类。定义了如何添加观察者,移除观察者,通知观察者更新的基本行为。
    • SubjectImpl1和SujectImpl2:是对主题的具体实现,可以通过实现Subject的接口实现不同种类的主题和中心对象。
    • Observer:观察者接口定义。定义观察者更新行为。
    • ObserverImpl1和ObserverImpl2:观察者的实现类,可以通过实现Observer接口实现不同的观察者,监听不同的主题。

    5.代码实例

    实例介绍

    实例实现了一个天气中心,向一个当前天气显示器上通知最新的气象数据:温度、湿度、压强。气象显示器会更新显示的数据,并实时显示。

    主题中心类:

    /**
     * 主题类
     * @author Misout
     * @date 2018-03-25 12:40:37
     */
    public interface Subject {
        /**
         * 注册添加观察者
         * @param observer
         */
        void registerObserver(Observer observer);
        /**
         * 移除观察者
         * @param observer
         */
        void removeObserver(Observer observer);
        /**
         * 更新或通知变更所有观察者
         */
        void notifyObservers();
    }
    

    具体主题实现类:

    /**
     * 具体主题实现类:一个天气数据中心
     * 一旦更新数据,实时通知观察者
     * @author Misout
     * @date 2018-03-25 12:51:19
     */
    public class WeatherData implements Subject {
        /** 已注册的观察者列表 */
        private List<Observer> observers;
        /** 温度 */
        private float temp;
        /** 湿度 */
        private float humidity;
        /** 压强 */
        private float pressure;
        public WeatherData() {
            observers = new ArrayList<Observer>();
        }
        @Override
        public void registerObserver(Observer observer) {
            observers.add(observer);
        }
        @Override
        public void removeObserver(Observer observer) {
            int index = observers.indexOf(observer);
            if(index >= 0) {
                observers.remove(index);
            }
        }
        @Override
        public void notifyObservers() {
            for (Observer observer : observers) {
                observer.update(temp, humidity, pressure);
            }
        }
        /**
         * 发生数据变化时,实时通知观察者
         */
        public void measurementsChanged() {
            notifyObservers();
        }
        public void setMeasurements(float temp, float humidity, float pressure) {
            this.temp = temp;
            this.humidity = humidity;
            this.pressure = pressure;
            measurementsChanged();
        }
        public float getTemp() {
            return temp;
        }
        public void setTemp(float temp) {
            this.temp = temp;
        }
        public float getHumidity() {
            return humidity;
        }
        public void setHumidity(float humidity) {
            this.humidity = humidity;
        }
        public float getPressure() {
            return pressure;
        }
        public void setPressure(float pressure) {
            this.pressure = pressure;
        }
    }
    

    观察者接口定义:

    /**
     * 观察者
     * @author Misout
     * @date 2018-03-25 12:40:28
     */
    public interface Observer {
        /**
         * 更新温度、湿度、压强.
         * 缺点:将更新的参数值直接放入型参,如果未来要增减观察指标,将不可扩展。
         * @param temp 温度
         * @param humidity 湿度
         * @param pressure 压强
         */
        void update(float temp, float humidity, float pressure);
    }
    

    观察者具体实现类:

    /**
     * @author Misout
     * @date 2018-03-25 13:33:58
     */
    public class CurrentConditionsDisplay 
            implements Observer{
        private float temp;
        private float humidity;
        private float pressure;
        private Subject weatherData;
        /**
         * 注册到指定的Subject,进行监听
         * @param weatherData
         */
        public CurrentConditionsDisplay(Subject weatherData) {
            this.weatherData = weatherData;
            weatherData.registerObserver(this);
        }
        @Override
        public void update(float temp, float humidity, 
                    float pressure) {
            this.temp = temp;
            this.humidity = humidity;
            this.pressure = pressure;
            display();
        }
        public void display() {
            System.out.println("Current conditions: " 
                    + temp + "F degrees and " + humidity 
                    + "% humidity and " + pressure 
                    + " pressure");
        }
    }
    

    测试代码:

    /**
     * @author Misout
     * @date 2018-03-25 13:37:49
     */
    public class WeatherStationTest {
        public static void main(String[] args) {
            // 创建一个主题实现类:天气数据中心
            WeatherData weatherData = new WeatherData();
            // 创建一个观察者:当前天气显示器,并注册到天气中心
            CurrentConditionsDisplay currentDisplay = 
                    new CurrentConditionsDisplay(weatherData);
            // 天气中心变更数据,自动通知到观察者
            weatherData.setMeasurements(37, 50, 39.4f);
        }
    }
    

    输出:

    Current conditions: 37.0F degrees and 50.0% humidity and 39.4 pressure
    

    6.JDK中的观察者模式

    在JDK中已经提供了一套观察者模式的实现:Observable类相当于这里的Subject,Observer接口相当于这里的Observer接口

    类图关系如下:

    JDK观察者模式

    值得注意的是,JDK中的主题类叫作Observable,是一个类,并非一个接口。这是一个缺陷,因为要想通过JDK的API实现观察者模式,必须继承Observable类,并不满足面对接口编程的设计原则,如果某个类想具有Observable和其他另一个父类的功能,就陷入两难的境地。因为Java类并不支持多继承。

    7.总结

    1、封装变化的部分。
    2、多用组合、少用继承:JDK中的观察者模式给了一个教训。
    3、针对接口编程,不针对实现编程。
    4、为对象之间的依赖关系达到松耦合设计而努力。

    推荐阅读:
    设计模式(一)策略模式

    相关文章

      网友评论

          本文标题:设计模式(二)观察者模式

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