首页 > 代码库 > 回调-> 观察者模式->反应堆模式
回调-> 观察者模式->反应堆模式
关于回调:
回调是观察者模式以及反应堆模式的基础
一句话,回调就是一种双向调用模式,什么意思呢,就是说,被调用方在被调用时也会调用对方,这就叫回调。“If you call me, i will call back”。
先看看这个可以说比较经典的使用回调的方式:
背景1:class A 实现接口inA
背景2:class A 中包含一个对于class B的引用b
背景3:class B有一个参数为InA的方法test(InA a)
class A的对象a调用B的方法传入自己(由于形参是个inA a),test(a) ——这一步相当于you call me.
然后b就可以在test方法中调用InA的方法(已经将形参:接口a的引用传入了) ——这一步相当于I call you back.
可以参考下面的代码:
//最基本的回调模式实现:public interface inA {public void callBacka();}public class A implements inA{//含有个B的实例B b=new B();@Overridepublic void callBacka() {// TODO Auto-generated method stubSystem.out.println("excute the method in class A");}}public class B {public void test(inA a){a.callBacka();}public void excuteB(){System.out.println("excute the method in class B");}}
可以看出来,A类可以通过a.b获得b的实例来调用b中的方法,执行完之后,在B类的对应方法中,可以通过传入的A的参数,来实现对于A的方法的回调,这个是很关键的。
回调还可以实现异步操作,比如说,你有一个复杂的问题解决不了,打电话给你的同学,你的同学说可以解决这个问题,但是需要一些时间,那么你不可能一直拿着电话在那里等,你会把你的电话号码告诉他,让他解决之后打电话通知你。回调就是体现在你的同学又反过来拨打你的号码。
结合到前面所分析的,你打电话给你同学就是【you call me】,你同学解决完之后打电话给你就是回调【i call you back】。
两个关键点:
1、A类中包含一个B的引用,作为其属性
2、B类的需要回去到A的方法中,包含一个方法,这个方法的形参是对于A类的引用。
3、回调方法需要用接口实现,这样A可以通过集成接口,实现不同类型的回调方式。
再总结一下:软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用;回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反(注意这个是与之前的的例子相反的),接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。(貌似仅仅是用途不同而已 实质上差不多)同步调用是三者当中最简单的,而回调又常常是异步调用的基础。
观察者模式(Observer)
观察者模相当于是回调模式的扩充。在观察者模式中,观察者相当于上面例子中的A,被观察者相当于上面例子中的B。不同的是有多个观察者,一个被观察者,也可以是多个。
观察者模式的官方定义:
观察者模式定义了对象间的一种一对多依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
当一个被观察者的状态发生改变 所有依赖它的对象都发生变化。
该模式的几个角色:
Subject(被观察的对象接口 ),规定ConcreteSubject的统一接口。
每个Subject可以有多个Observer,(通过在具体实现类中添加观察者引用的ArrayList或者其他类似方式来实现,这是实现回调方式的关键),观察者是先于被观察者创建的,并且要将对于观察者的引用加入到被观察者的ArrayList中,这样才能在被观察者的信息改变了之后通知对应的观察者。(因为观察者是先于被观察者而创建的 而最后要通过被观察者来调用观察者,进行信息的更新,即后创建的,反过来调用先创建的对象,所以是回调)
ConcreteSubject(具体被观察对象)
维护对所有具体观察者的引用的列表,状态发生变化时会发送通知给所有注册的观察者。(通过列表中对于obversor的引用,来是实现回调,更新观察者)
从功能上来讲,ConcreteSubjec至少要包含 addobservor(添加一个观察者) deletobservor(删除一个观察者) 以及updateobservor三个部分,通过updateobservoer来进行回调,对观察者进行更新,或者是通知观察者来执行相对应的事务。
Observer(观察者接口)
规定ConcreteObserver的统一接口;
定义了一个update()方法,在被观察对象状态改变时会被调用。
ConcreteObserver(具体观察者)
维护一个对ConcreteSubject的引用,(这个可以通过对于ConcreteSubject进行引用,以此来调用ConcreteSubject中的方法,比如添加删除之类的操作,这样的话,不用在main函数中生成ConcreteSubject的具体的类了,每一个observer都含有add delete的方法)
特定状态与ConcreteSubject同步,实现Observer接口,通过update()方法接收ConcreteSubject的通知。(回调过来的具体执行部分)
具体分析见下面的代码,将obversor写成了witcher。
//定义观察者接口public interface iWatcher { public void update(String str);}//定义被观察者接口public interface iSubject { public void add(iWatcher w); public void delete(iWatcher w); //修改观察者类中的信息 public void update(String str);}public class concreteWatcher implements iWatcher { private String str; private int id; public void setId(int id) { this.id=id; } public int getId(){ return id; } //构造函数 public concreteWatcher(String str,int id){ this.str=str; this.id=id; System.out.println("the str is created:"+str+this.getClass().hashCode()); } @Override public void update(String str) { // TODO Auto-generated method stub this.str=str; System.out.println(this.getId()+" the str is updated:"+str); } }public class concreteSubject implements iSubject{ //含有一个观察者的队列 list是观察者队列的引用 ArrayList<iWatcher>list=new ArrayList<iWatcher>(); @Override public void add(iWatcher w) { // TODO Auto-generated method stub list.add(w); } @Override public void delete(iWatcher w) { // TODO Auto-generated method stub list.remove(w); } //体现回调的是在这个地方 @Override public void update(String str) { // TODO Auto-generated method stub //由于List是自身类的属性 不用通过方法在去传了 //这里是一个回调 watcher中的方法去进行更新 for(iWatcher w :list){ w.update(str); } } }package com.designpatten.Observer;public class Test { //生成三个观察者 public static void main(String []args){ concreteWatcher a1=new concreteWatcher("watcher1",1); concreteWatcher a2=new concreteWatcher("watcher2",2); concreteWatcher a3=new concreteWatcher("watcher3",3); //生成一个被观者 即抽象主题 concreteSubject sub=new concreteSubject(); sub.add(a1); sub.add(a2); sub.add(a3); sub.update("update the information"); }}//执行结果/*the str is created:watcher11580958233the str is created:watcher21580958233the str is created:watcher315809582331 the str is updated:update the information2 the str is updated:update the information3 the str is updated:update the information*/
关于反应堆模式(reactor)
反应器模式(Reactor pattern)与观察者模式(Observer pattern)在这个方面极为相似:当一个主体发生改变时,所有依属体都得到通知。不过,观察者模式与单个事件源关联,而反应器模式则与多个事件源关联 。
Reactor Pattern 是一种为处理服务请求并发提交到一个或者多个服务处理程序的事件设计模式,当请求抵达后,服务处理程序使用多路分配策略,然后同步地派发这些请求至相关的请求处理程序。
Observer patten只是监听一个固定的主题,在reactor patten中,相当于subject的实现实例中同时包含了不同的Aarrylist每个对应一个事件,每一个事件被触发,传到subject中,相对应的Arraylist中引用的类就会被更新(所谓的进行注册过的事件)
在reactor模式中,资料中常常会提到一个Hook Method 即是钩子方法,这个是模板模式的一部分内容,具体的可以参考一下后面列出的链接。
这里就是简单总结一下:
从模板模式的角度来看,方法被分成三类:具体方法,抽象方法,钩子方法。
1、具体方法就是我们平时所写的最常见的最普通的方法。
2、抽象方法在java中就是abstract方法,就是所谓的继承,这个也比较常见。在一个执行过程中几个函数的出现顺序一致,但是每个步骤于在子类中可能有不同的实现,就直接继承,迪对不同的抽象类进行不同的实现即可,这个的核心思想是在父类中提供了一个算法的框架,子类只能遵从这个框架来,但是具体每个步骤的实现上可能有差别。最典型的就是sort函数,每次排序时,可以自定义排序规则,这个可能会设计到具体不同的领域,但是sort函数的整个实现的大的步骤,则是完全固定的。
3、钩子方法其实就是反过来了,利用钩子方法,子类可以一定程度上影响父类的执行流程,钩子方法的返回结果通常为bool型变量,常常将父类中(模板方法)的某一个步骤放在if语句中,如果钩子方法返回true则执行,返回false则不执行。在子类中可以根据实际情况对钩子方法进行覆盖,并对其默认返回值进行修改,从而确定合适的模板方法的执行流程,相当于是子类影响了父类(模板方法)的执行流程。
相关参考资料:
http://1025250620.iteye.com/blog/1378538
http://daimojingdeyu.iteye.com/blog/828696
http://blog.csdn.net/fengxinze/article/details/7319059(这个是翻译版本)
(肯定是logserver对象先要生成 才能注册到initial dispatcher中 才能进行回调 说实话 对于例子中的get_handler 看得还是有点晕晕乎乎 先记录在这里)
模板方法模式
http://blog.csdn.net/lenotang/article/details/2911246
http://blog.csdn.net/lovelion/article/details/8299927
其他各种网络资料