zoukankan      html  css  js  c++  java
  • 设计模式之观察者模式

    观察者模式

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

    举例

      现在有一个气象站,需要发布发布天气,气象站只提供数据,需要编写程序将天气发布给每一个用户,用户接收也可能有多种模式,有的是当前天气状况也有的是天气预报。

      这时候就可以使用观察者模式,进行一对多推送,观察者模式主要就是订阅、发布过程,用户订阅了天气信息,气象站对用户及时发布最新的天气信息,用户也可以随时取消订阅。

    observer

      如图

    • Subject接口: 主题接口,也就是被观察对象的接口
    • Observer接口: 观察者接口
    • DisplayElement接口: 展示接口
    • WeatherData: 具体的被观察对象
    • CurrentConditionDisplay: 当前天气状态的展示

      通过上图,就可以看出观察者模式的运行情况了,具体主题实现Subject接口,具体展示实现Observer和DisplayElement接口,Subject中有注册、移除、通知三个方法,这样就可以对观察者进行注册移除,并通知观察者。

    // 模拟天气站,发布天气
    public class WeatherStation
    {
        public static void main(String[] args)
        {
            WeatherData weatherData = new WeatherData();
    
            CurrentConditionDisplay current = new CurrentConditionDisplay(weatherData);
    
            weatherData.setMeasurement(35, 65, 30.4f);
            weatherData.setMeasurement(36, 67, 30.5f);
            weatherData.setMeasurement(34, 66, 30.5f);
    
            // 移除观察者
            current.remove();
            weatherData.setMeasurement(33, 62, 30.5f);
        }
    }
    

    输出结果

    当前状态: 温度 35.0度 湿度 65.0%
    当前状态: 温度 36.0度 湿度 67.0%
    当前状态: 温度 34.0度 湿度 66.0%

      这样就基本完成了气象站的需求,可以对观察者们发布最新的天气信息。

    Java Jdk中内置的观察者模式实现

    • Observable类: 对应上述的Subject,也就是被观察的对象要实现的接口
    • Observer接口: 对应上述的Observer接口,观察者实现的接口

      使用内置的对象来实现观察者模式整体上跟上述基本相同,但是Observable是一个类,是需要用继承方式来扩展。

      在Observable中,有一个setChanged()方法,在通知之前,需要调用这个方法,来表明状态已经改变了。

      在Observer中的update()方法有两个参数,一个是一个Observable对象,还有一个就是Observable对象“推”的一个对象。在jdk内置方法中,发布有两种形式,一种是"推",一种是"拉",在Observable类中的notifyObservers()方法里,可以带一个参数,代表是"推",推送给每一个观察者,也可以不带参数,就默认是"拉"方式,这样就变得更为灵活。

      但是Observable是一个类,而不是一个接口,这样在程序扩展性上也有了一些限制,如果可以满足需求,就可以直接使用,如果不行,那么只能自己写一套观察者模式出来,就像最前面那样。

    使用jdk中观察者的类

    import java.util.Observable;
    
    // 使用jdk提供的内置对象完成观察者模式
    public class WeatherData extends Observable
    {
        private float temperature;
        private float humidity;
        private float pressure;
    
        public WeatherData(){}
    
        public void measurementsChanged()
        {
            setChanged();
            notifyObservers();
        }
    
        public void setMeasurements(float temperature, float humidity, float pressure)
        {
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            measurementsChanged();
        }
    
        // 使用“拉”模式的时候,观察者通过这些方法来获取状态
        public float getTemperature()
        {
            return temperature;
        }
    
        public float getHumidity()
        {
            return humidity;
        }
    
        public float getPressure()
        {
            return pressure;
        }
    }
    
    import ObserverPattern.DisplayElement;
    
    import java.util.Observable;
    import java.util.Observer;
    
    // 展示当前状态
    public class CurrentConditionDisplay implements Observer, DisplayElement
    {
        Observable observable;
        private float temperature;
        private float humidity;
    
        public CurrentConditionDisplay(Observable observable)
        {
            this.observable = observable;
            observable.addObserver(this);
        }
    
        public void remove()
        {
            observable.deleteObserver(this);
        }
    
        public void update(Observable obs, Object arg)
        {
            if(obs instanceof WeatherData)
            {
                WeatherData weatherData = (WeatherData)obs;
                this.temperature = weatherData.getTemperature();
                this.humidity = weatherData.getHumidity();
                display();
            }
        }
    
        public void display()
        {
            System.out.println("当前状态: 温度 " + temperature + "度 " + " 湿度 " + humidity + "%");
        }
    }
    

      以上具体代码都可以在我的github中查看
      地址:https://github.com/yangliu0/DesignPatterns

  • 相关阅读:
    【测试】form表单完成html测试20道页面排列
    CSS选择器与CSS的继承,层叠和特殊性
    css语法特点和引入页面三种方式与其优先级
    10——PHP中的两种数组【索引数组】与【关联数组】
    C++走向远洋——66(十五周阅读程序)
    C++走向远洋——65(十五周、项目一)
    STL容器的使用
    STL迭代器的使用、正向、逆向输出双向链表中的所有元素
    C++走向远洋——64(项目三、数组类模板)
    C++走向远洋——63(项目二2、两个成员的类模板)
  • 原文地址:https://www.cnblogs.com/liuyang0/p/6271348.html
Copyright © 2011-2022 走看看