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

            观察者(Observer)设计模式定义了对象间的一种一对多的组合关系(一是发布者,多是观察者),以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新【即:信息即时同步】。为了实现松耦合,观察者和发布者之间的互动关系不是类之间的直接调用[对于观察者,发布者只需要知道其实现了某个接口(Oberver接口),至于观察者到底是谁,发布者并不在乎]。
     
             本质上, 观测者模式 = 发布者 + 观察者
     
            JDK提供了内置的观察者模式【java.util.Observable,java.util.Observer】,用户只需要定义具体的发布者和观察者。
     
    1. JDK内置的观察者模式
        1.1 发布者 : 继承Obsrevable类,是数据的拥有者。当数据发生更新时,发布者会通知依赖的观察者
    public class WeatherD extends Observable{
    
        private double temperature;
        private double humidity;
        private double pressure;
        
        public double getTemperature() {
            return temperature;
        }
        public double getHumidity() {
            return humidity;
        }
        public double getPressure() {
            return pressure;
        }
        
        public void setMeasurements(double temp, double humidity, double pressure){
            this.temperature = temp;
            this.humidity = humidity;
            this.pressure = pressure;
            double[] args = {temp,humidity,pressure};
    //注释一 setChanged();
    notifyObservers(args); } }

            1.1.1 注释一:setChanged()方法将changed状态置为true,只有changed状态置为true时,在调用notifyObservers()时才会通知观察者。setChanged()方法让你在通知观察者时具有更多的弹性【在某些场景下,并不是发布者的数据每一次更新都要通知观察者】。

    public void notifyObservers(Object arg) {
            /*
             * a temporary array buffer, used as a snapshot of the state of
             * current Observers.
             */
            Object[] arrLocal;
    
            synchronized (this) {
                /* We don't want the Observer doing callbacks into
                 * arbitrary code while holding its own Monitor.
                 * The code where we extract each Observable from
                 * the Vector and store the state of the Observer
                 * needs synchronization, but notifying observers
                 * does not (should not).  The worst result of any
                 * potential race-condition here is that:
                 * 1) a newly-added Observer will miss a
                 *   notification in progress
                 * 2) a recently unregistered Observer will be
                 *   wrongly notified when it doesn't care
                 */
                if (!changed)
                    return;
                arrLocal = obs.toArray();
                clearChanged();
            }
    
            for (int i = arrLocal.length-1; i>=0; i--)
                ((Observer)arrLocal[i]).update(this, arg);
        }

            1.1.2 可以调用clearChanged()将changed状态置为false,调用hasChanged()查看当前的changed的状态。

        1.2  观察者 :实现Observer接口,是数据的处理者。从发布者获取数据后,观察者会对数据进行处理
    public class ObserverB implements Observer {
        
        private double temperature;
        private double humidity;
        private double pressure;
        
        @Override
        public void update(Observable o, Object arg) {
            //注释一
    //1.push double[] args = (double[]) arg; this.temperature = args[0]; this.humidity = args[1]; this.pressure = args[2]; //2.pull WeatherD d = (WeatherD) o; this.temperature = d.getTemperature(); this.humidity = d.getHumidity(); this.pressure = d.getPressure(); printInfo(); } private void printInfo(){ StringBuilder info = new StringBuilder(); info.append("Current weather date is [temperature : ").append(this.temperature) .append(",humidity : ").append(this.humidity) .append(",pressure : ").append(this.pressure) .append("]."); System.out.println(info.toString()); } }

            1.2.1 注释一:Java内置的观察者模式,提供了push(推)和pull(拉)的方式传递数据【push:发布者将所有的数据推送给观察者;pull:观察者通过调用发布者的Getter方法获取需要的数据】 。(通常认为,push的方式更正确)

                   需要注意的是,Observable是一个类,如果发布者同时还需要具备另一个超类的行为,就会陷入两难,毕竟Java不支持多继承,它限制了Observable的复用潜力(而增加复用潜力是模式的原动力)。

                   【遇到此类情况,你能做的就是自定义一套观察者模式】

    2. 自定义观察者模式

               自定义观察者模式必须具备四个角色:抽象发布者、具体发布者、抽象观察者、具体观察者。

        2.1 抽象发布者

    public interface Subject {
    
        public void registerObserver(Observer o);
        
        public void removeObserver(Observer o);
        
        public void notifyObersers();
    }

        2.2 具体发布者

            通过接口实现发布者,避免了无法继承其它超类的局限。但是,也产生了一个新的问题,即:每创建一个观察者,都必须重写抽象观察者的方法。【当然,可以创建一个中间层,用来实现抽象发布者接口,同时继承其它超类。】

    public class WeatherData implements Subject{
    
        private double temperature;
        private double humidity;
        private double pressure;
        private List<Observer> observers;
        
        public WeatherData() {
            observers = new ArrayList<Observer>();
        }
        
        public double getTemperature() {
            return temperature;
        }
        public double getHumidity() {
            return humidity;
        }
        public double getPressure() {
            return pressure;
        }
        
        public void setMeasurements(double temp, double humidity, double pressure){
            this.temperature = temp;
            this.humidity = humidity;
            this.pressure = pressure;
            measurementsCharged();
        }
        
        private void measurementsCharged(){
            notifyObersers();
        }
        
        @Override
        public void registerObserver(Observer o) {
            observers.add(o);
        }
    
        @Override
        public void removeObserver(Observer o) {
            observers.remove(o);
        }
    
        @Override
        public void notifyObersers() {
            for (Observer observer : observers) {
                observer.update(temperature, humidity, pressure);
            }
        }
        
    }

        2.3 抽象观察者

    public interface Observer {
    
        public void update(double temp, double humidity, double pressure);
    
    }

        2.4 具体观察者

    public class ObserverA implements Observer {
        
        private double temperature;
        private double humidity;
        private double pressure;
    
        @Override
        public void update(double temp, double humidity, double pressure) {
            this.temperature = temp;
            this.humidity = humidity;
            this.pressure = pressure;
            printInfo();
        }
        
        private void printInfo(){
            StringBuilder info = new StringBuilder();
            info.append("Current weather date is [temperature : ").append(this.temperature)
                .append(",humidity : ").append(this.humidity)
                .append(",pressure : ").append(this.pressure)
                .append("].");
            System.out.println(info.toString());
        }
    
    }

    3. 参考资料

        3.1 百度百科:《观察者模式》

        3.2 O'Reilly:《Head First设计模式》

  • 相关阅读:
    一个表缺失索引发的CPU资源瓶颈案例
    SQLServer 版本之八大方法搞清 "我是谁"
    DBA成长路线
    SQL Server2016升级前几点自检
    SQL Server 2016白皮书
    <译>通过PowerShell工具跨多台服务器执行SQL脚本
    /lib64/libc.so.6: version `GLIBC_2.17' not found
    /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found
    HGT高程数据文件格式解析
    DEM高程数据下载资源
  • 原文地址:https://www.cnblogs.com/BlueStarWei/p/10320598.html
Copyright © 2011-2022 走看看