前言
了解设计模式的童鞋应该都知道观察者模式,类似于上图的结构,其中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,可以看到结果为:
观察对象为:com.sunny.MyObservable@60e53b93;传递参数为: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实现观察者模式的主要原理了。
欢迎小伙伴与我讨论哦~
本文欢迎转载,请注明本文地址:https://www.jianshu.com/p/e45a12e3ac60
网友评论