zoukankan      html  css  js  c++  java
  • 设计模式----行为型模式之观察者模式(Observer Pattern)

      下面是阅读《Head First设计模式》的笔记。

    观察者模式

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

    JDK API内置机制

      JDK1.0版本就已经包含了java.util.Observer和java.util.Observable,TODO。

      java.util.Observer是一个接口,所有使用内置机制实现观察者模式,都需要实现该接口。该接口只定义了一个方法 void update(Observable o, Object arg),实现该接口的类(观察者)需要重新该方法,当主题(可观察的)状态改变时,会通知观察者更新实时信息,每一个观察者获取到改变的数据,做出相应的实现(需求不一致),类似于书中介绍的状态布告板、统计布告板和预测布告板等。

      java.util.Observable是一个类,这个类或者继承改类的(继承基类的行为),内置构造和方法如图所示(省事截图):

      

      Observable类中的setChanged()方法提供了更多弹性,当继承该类是,可以调用该方法,根据自己的需求,适当地改变状态,再通知每一个观察者实现通知的功能。

    使用观察者模式实现的例子

       

    /**
     * 天气主题(可观察者/目标)
     * @author mjs
     * @version 1.0.0
     * @filename WeatherData.java
     * @time 2017-3-9 下午8:26:48
     * @copyright(C) 2017 **********有限公司
     */
    package com.shing.design.observerpattern;
    
    import java.util.Observable;
    
    public class WeatherData extends Observable {
        private float temperature; //温度
        private float humidity; //湿度
        private float pressure; //气压
        public float getTemperature() {
            return temperature;
        }
        
        public WeatherData() {
            // TODO Auto-generated constructor stub
        }
        /**
         * 改变状态,通知观察者(布告板)
         */
        public void measurementsChanged(){
            setChanged();
            notifyObservers();
        }
        
        /**
         * 当气象台检测到变化是调用该方法
         * @param temperature 温度
         * @param humidity 湿度
         * @param pressure 大气压
         */
        public void setMeasurements(float temperature, float humidity, float pressure){
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            measurementsChanged();
        }
        
        public void setTemperature(float temperature) {
            this.temperature = temperature;
        }
        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 mjs
     * @version 1.0.0
     * @filename DisplayElement.java
     * @time 2017-3-9 下午8:24:49
     * @copyright(C) 2017 **********有限公司
     */
    package com.shing.design.observerpattern;
    
    public interface DisplayElement {
        /**
         * 显示元素方法
         */
        void display();
    }
    /**
     * 目前状况布告板
     * @author mjs
     * @version 1.0.0
     * @filename CurrentConditionsDisplay.java
     * @time 2017-3-11 上午9:35:45
     * @copyright(C) 2017 **********有限公司
     */
    package com.shing.design.observerpattern;
    
    import java.util.Observable;
    import java.util.Observer;
    
    public class CurrentConditionsDisplay implements Observer, DisplayElement {
        Observable observable;
        private float temperature;
        private float humidity;
        
        
        /**
         * 初始化构造,并注册到气象台
         * @param observable
         */
        public CurrentConditionsDisplay(Observable observable) {
            super();
            this.observable = observable;
            observable.addObserver(this);
        }
    
        /* 
         * 布告板显示
         */
        public void display() {
            // TODO Auto-generated method stub
            System.out.println("【目前状况布告板】当前状况:" + temperature + "华摄氏度, " + humidity + "%湿度");
        }
    
        /* 
         * 
         */
        public void update(Observable obs, Object arg) {
            if(obs instanceof WeatherData){
                WeatherData weatherData = (WeatherData) obs;
                this.temperature = weatherData.getTemperature();
                this.humidity = weatherData.getHumidity();
                display();
            }
        }
    
    }
    /**
     * 预测布告板
     * @author mjs
     * @version 1.0.0
     * @filename ForecastDisplay.java
     * @time 2017-3-11 上午9:53:09
     * @copyright(C) 2017 **********有限公司
     */
    package com.shing.design.observerpattern;
    
    import java.util.Observable;
    import java.util.Observer;
    
    public class ForecastDisplay implements DisplayElement, Observer {
        Observable observable;
        private float currentPressure = 29.92f;
        private float lastPressure;
        /**
         * 初始化预测布告板,并注册在气象台
         * @param observable
         */
        public ForecastDisplay(Observable observable) {
            super();
            this.observable = observable;
            observable.addObserver(this);
        }
    
        /* 
         * 更新状态
         */
        public void update(Observable o, Object arg) {
            // TODO Auto-generated method stub
            if(o instanceof Observable){
                WeatherData weatherData = (WeatherData) o;
                lastPressure = currentPressure;
                currentPressure = weatherData.getPressure();
                display();
            }
        }
    
        /* 
         * 
         */
        public void display() {
            // TODO Auto-generated method stub
            System.out.println("【预测布告板】当前气压:" + currentPressure + ",最新气压:" + lastPressure);
        }
    
    }
    /**
     * 测试类
     * @author mjs
     * @version 1.0.0
     * @filename Test.java
     * @time 2017-3-11 上午10:21:59
     * @copyright(C) 2017 **********有限公司
     */
    package com.shing.design.observerpattern;
    
    
    public class Test {
        public static void main(String[] args) {
            WeatherData weatherDate = new WeatherData();
            CurrentConditionsDisplay conditionsDisplay = new CurrentConditionsDisplay(weatherDate);
            ForecastDisplay forecastDisplay = new ForecastDisplay(weatherDate);
            weatherDate.setMeasurements(57, 87, 110);
        }
    }
    /**
        Console:  
        【预测布告板】当前气压:110.0,最新气压:29.92
        【目前状况布告板】当前状况:57.0华摄氏度, 87.0%湿度
    */

    推模型和拉模型

      推模型: 主题对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。

      拉模型:主题对象在通知观察者的时候,只传递少量信息。(上述的例子就是该种模型,如果推模型,请自行脑补哈)。

      注:JDK API中都实现了观察者模式,JavaBeans和Swing,Swing API中JButton类所实现的超类AbstractButton,会看到许多增加与删除倾听者(listener)的方法,这些方法可以让观察者感应到Swing组件的不同类型事件。

    结束语

     多学习一点,人生多一分精彩!

      

  • 相关阅读:
    hdu 1159 Common Subsequence(最长公共子序列)
    Codeforces Round #313 (Div. 2)
    cf 558A Lala Land and Apple Trees
    zoj 2193 Window Pains
    poj 2031 Building a Space Station(最小生成树)
    zoj 1060 Sorting It All Out(拓扑排序)
    拓扑排序
    poj 1287 Networking
    zoj 1586 QS Network
    poj 1679 The Unique MST
  • 原文地址:https://www.cnblogs.com/mjs154/p/6527442.html
Copyright © 2011-2022 走看看