• 【设计模式】观察者模式


    一、简介

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

    有很多项目都用到了该设计模式,比如Spring的事件机制、消息队列等。
    Java提供了两个接口java.util.Observablejava.util.Observer,也可以利用这两个接口实现。

    类图如下:

     

    观察者模式类图
    观察者模式类图

     

    二、示例

    需求背景是气象站发布天气数据,所有订阅了气象站的布告板显示天气数据。
    先上类图:

     

    enter description here
    enter description here

    主题接口

     

    /**
     * 主题接口
     * Created by 2YSP on 2018/1/24.
     */
    public interface Subject {
        /**
         * 注册一个观察者
         * @param observer
         */
         void registerObserver(Observer observer);
    
        /**
         * 移除一个观察者
         * @param observer
         */
         void removeObserver(Observer observer);
    
        /**
         * 通知所有观察者
         */
         void notifyObservers();
    }
    

    观察者接口

    public interface Observer {
        /**
         * 所有观察者必须实现该方法,
         * 当气象观测值改变时,主题会把这些状态值当参数传给观察者
         * @param temp
         * @param humidity
         * @param pressure
         */
         void update(float temp,float humidity,float pressure);
    }
    

    具体主题WeatherData

    public class WeatherData implements Subject {
        /**
         * 注册的观察者集合
         */
        private List<Observer> observers;
        /**
         * 温度
         */
        private float temperature;
        /**
         * 湿度
         */
        private float humidity;
        /**
         * 气压
         */
        private float pressure;
    
        public WeatherData(){
            observers = new ArrayList();
        }
    
        @Override
        public void registerObserver(Observer observer) {
            observers.add(observer);
        }
    
        @Override
        public void removeObserver(Observer observer) {
            if (observers.contains(observer)){
                observers.remove(observer);
            }
        }
    
        @Override
        public void notifyObservers() {
            observers.forEach(o -> {
                o.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();
        }
    
        //WeatherData的其他方法
    }
    

    当前状况布告板,这里只弄了一个,还可以根据自己的需求定义其他种类的布告板。

    /**
     * 当前状况布告板(还可以建立其他观察者)
     * Created by 2YSP on 2018/1/24.
     */
    public class CurrentConditionDisplay implements Observer,DisplayElement {
        /**
         * 温度
         */
        private float temperature;
        /**
         * 湿度
         */
        private float humidity;
    
        private Subject weatherData;
    
        public CurrentConditionDisplay(Subject weatherData){
            this.weatherData = weatherData;
            weatherData.registerObserver(this);
        }
    
        @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();
        }
    }
    

    DisplayElement

    public interface DisplayElement {
        /**
         * 布告板显示气象数据
         */
        void display();
    }
    

    气象站

    public class WeatherStation {
    
        public static void main(String[] args) {
            WeatherData weatherData = new WeatherData();
            CurrentConditionDisplay currentCondition = new CurrentConditionDisplay(weatherData);
    
            weatherData.setMeasurements(80,65,30.4f);
        }
    }
    

    运行main方法控制台输出如下,说明布告板收到了消息并自动更新。

    Current conditions: 80.0F degrees and 65.0% humidity

    注意: 这里是通过构造方法传入具体主题,然后调用具体主题的registerObserver(Observer observer) 方法来实现注册观察者的。在实际项目中,我们可以通过在spring的xml配置文件上配置进行观察者的注册,这样更加灵活,不用修改代码。需要给WeatherData添加一个setObservers(List observers) 方法,利用set方法注入。

            <bean id="weatherData" class="xx.xx.WeatherData">
                <property name="observers">
                    <list>
                        <ref bean="currentConditionDisplay"/>
                    </list>
                </property>
            </bean>
    
  • 相关阅读:
    Begin Example with Override Encoded SOAP XML Serialization
    State Machine Terminology
    How to: Specify an Alternate Element Name for an XML Stream
    How to: Publish Metadata for a WCF Service.(What is the Metadata Exchange Endpoint purpose.)
    Beginning Guide With Controlling XML Serialization Using Attributes(XmlSerializaiton of Array)
    Workflow 4.0 Hosting Extensions
    What can we do in the CacheMetaData Method of Activity
    How and Why to use the System.servicemodel.MessageParameterAttribute in WCF
    How to: Begin Sample with Serialization and Deserialization an Object
    A Test WCF Service without anything of config.
  • 原文地址:https://www.cnblogs.com/2YSP/p/11602078.html
Copyright © 2020-2023  润新知