• 设计模式整理_观察者模式


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

      被观测的对象称为主题(Subject),观察被观测的对象的对象称为观察者(Observer).

      现实中的观察者模式:例如报纸的订阅.不同人(Observer)向报社(Subject)订购报纸,当报社出品了新的报纸的时候,将会通知它的订阅者,送报纸.中途订阅者可以取消订阅,此时报社就不再给他报纸.但是只要报社一直存在,就可以有人订阅报纸.

      在JavaGUI中,就有观察者模式的体现,例如Button按钮的实现.JButton会有增加和删除Listener(倾听者)的方法.

      观察者模式提供了一种对象设计,让主题和观察者之间松耦合.关于观察者的一切,主题只知道观察者实现了某个接口,主题不需要知道观察者的实现类是谁,做了什么或其他任何细节.在运行时候,我们可以用新的观察者来取代现有的观察者,主题不会收到任何影响.新类型观察者出现,主题也不需要作出修改,只需要在新的类里面实现了观察者接口,然后注册为观察者即可.改变主题或观察者的任意一方,并不会影响另一方,因为两者是松耦合的,所有可以自由改变.

      示例:

      

    import java.util.ArrayList;
    /*
     * 演示主题.
     * */
    public interface Subject {
        public void registerObserver(Observer o);        //注册观察者
        public void removeObserver(Observer o);            //移除观察者
        public void notifyObservers();        //主题状态发生变化的时候,通知观察者。
    }
    class WeatherData implements Subject {
        private ArrayList<Observer> observers;    //观察者队列,不需要知道观察者的具体实现细节。
        private float temperature;
        private float humidity;
        private float pressure;
        
        public WeatherData() {
            observers=new ArrayList<Observer>();
        }
        @Override
        public void registerObserver(Observer o) {
            observers.add(o);
            System.out.println("注册一项观察者.");
        }
    
        @Override
        public void removeObserver(Observer o) {
            int i=observers.indexOf(o);
            if(i>=0)
            observers.remove(o);
            System.out.println("移除一项观察者.");
        }
    
        @Override
        public void notifyObservers() {
            for (int i = 0; i < observers.size(); i++) {
                /*
                 * 这里由于每个观察者都实现了Observer接口,因此我们知道如何去通知观察者来做出更新动作。
                 * */
                observers.get(i).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();
        }
    }
    /*
     * 演示观察者
     * */
    public interface Observer {
        public void update(float temp,float humidity,float pressure);
    }
    class CurrentConditionObserver implements Observer/*实现了观察者接口,可以获得改变。*/ {
        private float temperature;
        private float humidity;
        private Subject weatherData;
        
        public CurrentConditionObserver(Subject weatherData) {
            this.weatherData = weatherData;    //构造器需要WeatherData对象作为注册时使用。
            weatherData.registerObserver(this);
        }
    
        @Override
        public void update(float temp, float humidity, float pressure) {
            this.temperature=temp;
            this.humidity=humidity;
            display();
        }
    
        public void display() {
            System.out.println("Current Conditions:"+temperature+
                    " F degrees and "+humidity+"% humidity");
        }
        
    }
    /*
     * 测试主题和观察者.这里只用了一个观察者.
     * */
    public class Test {
        public static void main(String[] args) {
            WeatherData data=new WeatherData();
            CurrentConditionObserver obs=new CurrentConditionObserver(data);
            data.setMeasurements(80, 65, 30);
            data.setMeasurements(82, 70, 29.2f);
            data.setMeasurements(84, 0, 29.2f);
            data.removeObserver(obs);
        }
    }

      类图如下:

      实际上Java为我们提供了观察者和被观察者的便捷实现,即Observable类和Observer接口,被观察者只需要继承Observable类即可实现被观察的功能,而观察者只需要实现Observable接口即可.下面是示例,利用Java给定的观察者和被观察者对象,对代码做出了调整:

      

    /*
     * 演示主题.
     * */
    import java.util.Observable;
    
    class WeatherData extends Observable {
        private float temperature;
        private float humidity;
        private float pressure;
        //不再需要继承观察者而建立数据结构了.实际上Observable类已经为我们做好了这件事情.
        public WeatherData() {
        }
        public float getTemperature() {
            return temperature;
        }
        
        
        public float getHumidity() {
            return humidity;
        }
        
        
        public float getPressure() {
            return pressure;
        }
        
        
        public void measurementsChanged() /*当状态发生改变的时候,需要通知观察者*/{
            setChanged();    //调用notifyObservers方法之前,需要先调用setChanged来指示状态改变
            notifyObservers();
        }
        
        public void setMeasurements(float temperature,float humidity,float pressure) {
            this.temperature=temperature;
            this.humidity=humidity;
            this.pressure=pressure;
            measurementsChanged();
        }
    }
    import java.util.Observable;
    import java.util.Observer;
    
    /*
     * 演示观察者
     * */
    class CurrentConditionObserver implements Observer/*实现了观察者接口,可以获得改变。*/ {
        private float temperature;
        private float humidity;
        Observable obs;
        
        public CurrentConditionObserver(Observable weatherData) {
            this.obs = weatherData;    //构造器需要Observable对象作为注册时使用。
            weatherData.addObserver(this);
        }
    
        public void display() {
            System.out.println("Current Conditions:"+temperature+
                    " F degrees and "+humidity+"% humidity");
        }
    
        @Override
        public void update(Observable o, Object arg) {    //覆盖update方法,从Observable对象中获取值
            if(o instanceof WeatherData) {
                WeatherData data=(WeatherData) o;
                this.temperature=data.getTemperature();
                this.humidity=data.getHumidity();
                display();
            }
        }
        
    }

      但是实际上Java提供的这种机制是有缺陷的,因为Observable是一个类,因此只能继承来实现,这要求被观察的对象没有父类,另外一方面,也违反了设计模式当中的"多用组合,少用继承的原则,因此,有必要的时候,还是需要自己来实现观察者对象和被观察者对象.

      

  • 相关阅读:
    Web前端浏览器兼容性问题及解决方案
    JS
    vue element-ui 重置样式问题
    学习的一些文章链接
    打开新世界的第一步:学习servlet
    java学习初体验之课后习题
    下载、安装jdk8(Windows下)并配置变量环境
    下载PhpStorm并进行激活
    WCF+NHibernate 序列化
    wcf 证书+ssl+自定义用户名密码
  • 原文地址:https://www.cnblogs.com/hlhdidi/p/5596588.html
Copyright © 2020-2023  润新知