观察者模式梳理二

顾名思义就是观察者从被观察者身上拉取自己需要的数据!

类结构图同拉的方式,不过具体代码上会有点区别!
本案中被观察者接口和观察者接口我们采用的是JDK自带的API来写!里面已经考虑了多并发的情况。但是他的观察者是一个类,又因为java是单继承的,所以在这点稍微有点不好!但是想把一些基础的功能搞定的话,必须使用类来操作。矛盾啊!

被观察者的实现

package com.alibaba.test.observer.api;

import java.util.Observable;

public class WeatherData2 extends Observable {

    private float temperature;

    private float humidity;

    private float pressure;

    public void setMeaturements(float temperature, float humidity, float pressure) {

        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        changed();
    }

    public void changed() {

        setChanged(); //这步很有必要,这样我们就可以有更多的弹性,可以适当的通知观察者,比如说在10秒通知一次,那么就不需要每次实时很敏感的通知!
                      // if time & 10 == 0 {....}

        notifyObservers();
    }

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }

    //测试代码,这里可以清晰的看到,没有建立观察者和被观察者之间的关系,两者之间关系的确立时在观察者内!具体看观察者的代码!
    public static void main(String[] args) {
        WeatherData2 data2 = new WeatherData2();
        new BObserver(data2);
        data2.setMeaturements(0.6f, 0.9f, 2.0f);

    }

}

 

观察者的实现:

package com.alibaba.test.observer.api;

import java.util.Observable;
import java.util.Observer;

import com.alibaba.test.observer.DisplayMent;

public class BObserver implements Observer, DisplayMent {

    private float      t;
    private float      h;

    private Observable o;

   //这里将自己加入了观察者的队列中!
    public BObserver(Observable o) {
        this.o = o;
        this.o.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {

        //对于被观察者对象的数据封装起来,观察者自己主动获取需要的数据,如果做的更好的话,可以再建立一个上下文来封装数据
        if (o instanceof WeatherData2) {

            //这点也非常重要,我们可以利用JDK的观察者模式添加多个观察者,然后通过判断的方式来获取自己需要的数据,但是又会有一个问题,被观察对象是继承了Observer,那么在有多个不同类型或者是纬度的被观察者时,会造成一定的性能问题。故在某些情况下有必要做下区分!或者自己重写JDK的Observer
            WeatherData2 temp = (WeatherData2) o;
            this.t = temp.getTemperature();
            this.h = temp.getHumidity();
            display();

        }

    }

    @Override
    public void display() {
        System.out.println("the temperature is:" + t + " the humidity is :" + h);
    }

}

 

 

问题;
JDK的 Observer内部实现是vector + syncd的方式,防止多并发,有必要改写下!
可以看下他的通知所有观察者的实现:

  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);
    }

 

采用JDK版本的缺陷:
     1. 主题也就是被观察者是一个类,在JAVA中是单继承的方式,如果继承了这个类,就无法继承其他的方式
     2. 也因为是类,并且setChanged()是priotected 那么就必须采用继承的方式,违法的多用组合,少用继承的原则!
    
好的做法是重写这个observer,因为这个类出现的比较早,在考虑多线程方面,采用的都是早期的类,可以换用JDK5后的并发包!


要点总结:
 1.被观察者对象持有观察者的对象集合
 2.被观察者拥有添加,删除,通知所有观察者对象的行为
 3.方式有推和拉两种,两者的本质区别是一种把添加观察对象的操作在被观察者这边,另一种是在观察者对象将自己添加到被观察者对象集合中,本质上是一样的
 4.有多个观察者时,不需要依赖特定的顺序
 
  使用场景:
    图形界面编程的 SWING AWT GWT等,触发监听器!

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值