本文也是在查阅了各种资料下总结的,有什么问题还望各位大牛指正~
一. 基本概念
回调是一种双向调用的模式。被调用方在接口被调用时也会调用对方的接口。恩,具体来说,就是调用者A调用了被调用者B的方法,然后在B的这个方法体内又调用了A的方法。概念听起来很抽象。举个例子说明下,比如今天你去饭店吃饭,可是人满需要排队,于是你在饭店登记了一下(告诉他们你的手机号),告知他们如果有地方了就电话联系你。这是一个回调应用于异步的经典场景。你(调用者)在调用饭店(被调用者)的方法服务时,注册(登记)了自己的方法(电话通知你)。然后在饭店为你服务的过程中,又回调了你这个方法。
这样做有什么好处呢?
1. 异步:因为饭店现在满员,为你服务很慢,这个时候你就可以把等待的时间用来干别的事情(而不是空等待),等到饭店通知你了之后,再继续吃饭。
2. 模板:可能不同的客户需要不同的通知方式(不仅限于电话通知),饭店可以忽略这些,使用同一种处理方式,一个个叫号,到了之后,就按照当初客户登记的方式去通知客户。但是客户登记的这个方式必须符合饭店统一的规范。
二. 具体实现以及应用场景
1. C语言,主要是利用函数指针来进行的。举一个应用于模板的例子:
max
函数之所以能对一组任意类型的对象进行操作,关键在于传给max
的是指向对象的指针所构成的数组,而不是对象本身所构成的数组,这样max
不必关心对象到底是什么类型,只需转给比较函数cmp
,然后根据比较结果做相应操作即可,cmp
是调用者提供的回调函数,调用者当然知道对象是什么类型以及如何比较。
回调的体现:调用者调用了max函数(被调用者),同时将比较规则的函数指针cmp_student传给了max函数。而max函数又调用了调用者提供cmp_student函数。这就体现了回调。
2. java语言,主要是使用接口和抽象类来实现。举例如下:
应用于异步:
//定义一个接口,相当于饭店的通知规范,想要我通知你成功,必须符合规范
public interface CallBackInterface {
void notify();
}
public class Restaurant {
public void service(CallBackInterface callBack){
checkseats();
if(hasSeat())
notify();
}
}
//符合饭店规范的我的通知方式
public class ConsumerNotifier implements CallBackInterface {
public void notify(){
giveAPhoneCall();
}
}
public class Consumer {
public void getService(){
getInRestaurant();
Restaurant restaurant = new Restaurant();
restaurant.service(new ConsumerNotifier());//登记我的通知方式
}
}
应用于模板:
public interface CallBackInterface {
void execute();//回调方法
}
public class TestTemplate {
public void doInTest(CallBackInterface callBack){
System. out .println( "same initilize" );
callBack.execute();
System. out .println( "same release" );
}
public void action1(){
doInTest( new CallBackInterface(){
public void execute(){
System. out .println( "action1" );
};
});
}
public void action2(){
doInTest( new CallBackInterface(){
public void execute(){
System. out .println( "action2" );
};
});
}
public static void main(String args[]){
TestTemplate t = new TestTemplate();
t.action1();
t.action2();
}
}
输出结果:
same initilize
action1
same release
same initilize
action2
same release
action1 ,action2为两个不同功能的函数,但是他们具有完全相同的部分(一般为相同的初始化 和清理工作)和不同的部分。如hibernate操作中都有获得sessionFactory 创建session等操作,CRUD完了之后,都有关闭session等操作。这是相同的部分。不同的部分就是具体的CRUD工作。那么我们就可以如例子一样在doInTest里面写好创建session和结束session的工作。CRUD操作则使用同样的接口。而如action1,和action2 一样 提供对外的CRUD接口则只关注具体操作 而不用管session的管理工作了。大家可以参见下 hibernateTemplate
回调的体现:
此时的调用者是action1方法,被调用者是doInTest方法。action1方法调用doInTest方法,同时提供了callBackInterface的实现。被调用者doInTest中又调用了调用者action1所提供的
三. 总结:
回调单纯来讲只是一种调用模式和该概念,抛开其应用场景来讲是没有意义的。其应用场景主要有异步和模板方法两种,着重点分别在于回调的时间以及回调函数的多样性。在C语言和Java语言两种场景有着不同的实现方式。我们在实际学习中更多的是注重应用场景并思考回调函数在应用场景中所带来的好处,并且思考在实际应用中使用的那些技术使用了回调函数(如hibernateTemplate,事件通知机制等)