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组件的不同类型事件。

    结束语

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

      

  • 相关阅读:
    DGA域名可以是色情网站域名
    使用cloudflare加速你的网站隐藏你的网站IP
    167. Two Sum II
    leetcode 563. Binary Tree Tilt
    python 多线程
    leetcode 404. Sum of Left Leaves
    leetcode 100. Same Tree
    leetcode 383. Ransom Note
    leetcode 122. Best Time to Buy and Sell Stock II
    天津Uber优步司机奖励政策(12月28日到12月29日)
  • 原文地址:https://www.cnblogs.com/mjs154/p/6527442.html
Copyright © 2011-2022 走看看