谈谈java中的观察者模式

谈谈java中的观察者模式

前言

了解设计模式的童鞋应该都知道观察者模式,类似于上图的结构,其中Observer作为观察者,Observable则作为被观察者,Observable的状态改变会给注册的Observer进行通知,考虑易用和低耦合,保证高度的协作。

Demo展示

我们首先来看一下demo,也就是上图类图中所展示的程序,MyObservable非常简单,只是继承了Observable:

public class MyObservable extends Observable{


    public static void main(String[] args) {

        MyObservable myObservable = new MyObservable();
        myObservable.addObserver(new MyObserver());

        myObservable.setChanged();
        myObservable.notifyObservers("aaa");

    }
}

此处为了简化结构,直接将main方法写在MyObservable中用于进行效果的测试,main中我们先实例化了MyObservable类,并且将一个MyObserver实例用addObserver方法加入它的观察者列表中,然后通过setChanged改变changed的状态值,随后便可以notifyObservers,里面可以带参数做消息传递,也可以不带参数。关于changed,是因为只有该变量为true的情况下,才会进行通知,否则notifyObservers是无法通知到具体Observer的。

MyObserver的结构也非常简单,由于继承了Observer接口,因此需要实现它的抽象方法update,这个方法也是用于接收Observable发来的通知并执行相应的处理逻辑的:

public class MyObserver implements Observer{

    public void update(Observable o, Object arg) {

        System.out.println("观察对象为:" + o + ";传递参数为:" + arg);

    }
}

运行一下demo,可以看到结果为:

观察对象为:[email protected];传递参数为:aaa

而在注释了setChanged方法之后,会发现没有任何输出,可以理解为,并没有真正通知到Observer。

原理解析

原理非常简单,查看Observable源码即可。其实从类图中就可以看出一些端倪,Observable中只有两个变量,一个是changed,一个是obs,从之前的分析可以看出changed只是一个状态指示的变量,那么obs应该就是一个用于存储Observer实例的变量了,它具体是用一个Vector来进行存储的。

private boolean changed = false;
private Vector<Observer> obs;

这样的情况下,我们很容易就可以猜测,obs的初始化应该是在Observable的构造方法中实现的,果不其然,构造方法也仅仅只是完成了obs的初始化:

public Observable() {
        obs = new Vector<>();
    }

然后我们更为关心的是Observable与Observer之间的关系,那么就是重点关注两个方法,addObserver和notifyObservers。addObserver很显然,里面的主要操作是将作为参数传入的Observer加入到Vector中:

public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }

notifyObservers则是逐一通知Observer的过程,不过在这个方法中会检查changed的值,以及会在通知完成后对changed归零(其中clearChanged方法就是将changed变量重新置为false):

public void notifyObservers(Object arg) {
        Object[] arrLocal;

        synchronized (this) {
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }

到这里基本上整个基于jdk实现的观察者模式的原理已经非常明了了,另外值得注意的一个点是,这个实现中用了一些措施来使它线程安全。比如,使用线程安全的容器Vector,addObserver方法进行了枷锁,在notifyObservers方法中,有一个操作进行了加锁:

synchronized (this) {
    if (!changed)
        return;
    arrLocal = obs.toArray();
    clearChanged();
}

这里主要确保了对changed变量的验证和清零操作以及将obs中的元素赋值给arrLocal的过程是原子操作,这里减少了锁的粒度,提高并发性,也因此大家能明白为何需要arrLocal这个变量了,随后对arrLocal数组进行便利并逐一通知则不需要加锁了,因为arrLocal已经是一个本地变量,并未暴露。

综上,就是基于jdk实现观察者模式的主要原理了。
欢迎小伙伴与我讨论哦~

邮箱:[email protected]

本文欢迎转载,请注明本文地址:https://blog.****.net/m0_37595562/article/details/83269225