这几天review公司的代码,在查资料的过程中发现Java SDK中竟然自带了Observer和Observable类,有点出乎我意料。下班之后带着好奇的心态,使用了一下,竟然发现还挺好用。在这里也写一篇博客来记录一下整个实践过程。
为了便于理解,先来讲个出版社和读者的故事吧:很久很久以前,有一家备受欢迎的出版社和一群忠实的读者,每次出版社的新书出版,读者们都会收到来信。后来,互联网时代到了,为了更好的服务读者,出版社编写了一套系统,每次新书发布,这套系统都会自动地给读者分发图书,读者朋友在收到书之后也都会向出版社报告。
那么这套系统是怎么实现的呢,我们来拆分一下需求:
首先是出版社,作为分发的主体,由于时刻被读者朋友们盯着,肯定是被观察者了,整个分发过程中作为信息源头,负责将图书信息分发给读者。
其次是读者朋友,作为接受信息的主体,时刻观察着出版社的动向,只要出版社新书发布,马上就会收到消息,并且还会给出版社一个收到图书的报告。在这里,把他们作为观察者Observer。
好了,故事讲完了,下面开始扒了猛干。
Talk is cheap,show me the code.先来贴个小代码
public class Reader implements Observer {
@Override
public void update(Observable o, Object arg) {
// TODO Auto-generated method stub
System.out.println("Observable:" +o.getClass()+ "get:" + arg.toString());
}
}
这里的Observer就是Java原生的接口了,我们在使用的时候只需要实现里面的update方法即可,当数据更新的时候会由Observable类内部持有的对象进行回调,整个过程完全自动化。
下面再来看一下出版社吧
public class Publisher extends Observable {
public void setData(){
this.setChanged();
}
}
这里的Publisher继承了Observable类,通过观察源码我们不难发现,Observable中的setData是Protect修饰的,也就是说我们在SDK包的外部无法进行访问,为了能够使用这个改变通知数据的功能,我们在这里Override了setData方法,并且调用了setChanged方法来来改变相应的数据开关,至于什么是数据开关,大家先不用关心,在通知数据改变的过程中会交由父方法进行检查。
好了,现在基础类写好了,让我们的系统跑起来
public class ObserverTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Publisher publisher = new Publisher();
Reader reader1 = new Reader();
Reader reader2 = new Reader();
publisher.addObserver(reader1);
publisher.addObserver(reader2);
publisher.setData();
publisher.notifyObservers("收到图书");
System.out.println("ObserverCount:" + publisher.countObservers());
}
}
在上面的代码中我们一共做了以下几件事:
- 创建了一个出版社对象
- 找来了两名热心读者
- 把热心读者加入了出版社关怀,以便在出版社发出消息的时候这两名读者能够收到消息
- 出版社马上有了动作,新书出版了,出版社扳动了消息开关,准备推送消息。
- 出版社做出了具体的消息推送动作:告诉读者,如果你们收到消息,就告诉我一下:收到图书
- 最后出版社统计了一下读者人数。
让我们来看一下最后到底发生了什么吧:
Observable:class observerTest.Publisherget:收到图书
Observable:class observerTest.Publisherget:收到图书
ObserverCount:2
看,读者们收到了图书,并且向出版社做出了回应,一次完美的图书发布过程就此完毕。
到了这里,故事也就讲完了。投过故事,我们回头来想一下,这个故事的本质是什么?
可能就是观察者和被观察者设计模式吧,也就是我们俗称的回调。
以我所见,观察者和被观察者设计模式最核心的动作可能就是观察者的注册动作了,在这个故事中也就是出版商将读者加入关怀的动作。少了这个动作,可能任何人都没办法将二者联系起来,更别提什么回调了。
好了,故事讲完了,你明白这种设计模式了吗?