回调机制深入剖析
来源:互联网 发布:淘宝客服双十一感受 编辑:程序博客网 时间:2024/06/05 17:30
问题的提出
什么是回调机制?采用回调机制有什么好处?不同的语言,如C,C++,Java等都有哪些措施来支持这种回调机制?
要回答上述问题,我们需要先回答这样一个问题:为什么需要函数调用?又为什么需要函数?!
是的,如果你够厉害,你都不需要函数,所以也就不需要函数调用,也就更不需要回调函数这个东西了!从头到尾,也许,一个Main函数就可以搞定所有的事情。。。
简单的函数调用
从原理上来说,的确可以这样做,远古时代的机器码,汇编代码不都是这样过来的吗?!但是,实际的情况是,你必须要函数,原因是:随着软件的代码量的增加,你必须要有一种结构化,可控的,可理解(。。。等等好处)的方式来管理你的代码,所以,函数就这样诞生了。
有了函数,也就有了调用者(Caller)和被调者(Callee)的概念,使用方式如下图所示:
这种使用方式很简单,只要学过任何一门高级语言的人都能理解。
示例代码
Void Caller()
{
Callee(Para para1, …)
}
简单函数调用的局限性
下面说说这种调用方式的局限性,以此来引出回调函数的概念,并说明回调函数所能带来的在程序设计上的灵活性。
简单的函数调用具有以下几个缺点:
1. Callee只能从Caller那里得到para1等一些少量的参数信息,它(Callee)不能够感知到Caller的存在。这时候,如果我们希望Callee能够在其运行时,能够知道Caller在哪里,并且能够利用Caller的一些资源(比如,Caller的一些功能函数【这就是回调!】),那么,这种简单的调用方式是不能满足我们的要求的
2. 示例代码中的Caller和Callee是紧密耦合的,这就很不利于扩展。比如:我们现在有多个Callee(Callee1,Callee2,…,),我们希望能够在运行时,根据不同的外部变化的条件来决定调用哪个具体的Callee,以获得更大的灵活性。
回调函数
针对上述两个缺点,回调机制能够很好的帮我们解决这些问题。而在不同的语言上,回调机制的表现形式也有所不同,总结如下:
C: 函数指针
C++: 函数指针,函数对象,基类或抽象类(多态机制)
Java:抽象类,接口
具体的实现代码,可参看我的另外两篇博文:
#include <iostream>using namespace std;class Strategy//基类接口{public:virtual void action() = 0;};class PlanA : public Strategy//具体类1{public:void action(){cout << " strategy plan A " << endl;}};class PlanB: public Strategy//具体类2{public:void action(){cout << "strategy plan B" << endl;}};//客户端调用了流程中的函数:takeAction,然后,takeAction又回调了客户端所编写的函数strategy.action() (所以,该函数被称为回调函数)void takeAction(Strategy *strategy)//根据传入不同的实际类型,采取不同的策略{cout << "is taking action..." << endl;strategy->action();}void main()//测试{PlanA pa;takeAction(&pa);PlanB pb;takeAction(&pb);}
#include <iostream>using namespace std;void planA(char ch) //回调函数1{cout << "planA" << endl;}void planB(char ch)//回调函数2{cout << "planB" << endl;}typedef void (*plan) (char);//回调函数的函数指针void takeAction(char otherpara, plan p) //调用函数,在函数体的某处将调用回调函数{cout << "is taking action : " << otherpara << endl;p(otherpara);}typedef char Situation;//用于描述不同的状况,以此作为采取不同策略的依据void strategy(Situation situation) //策略的定义,不同的situation下,采取不同的策略{if (situation == 'A'){takeAction(situation, planA);}if (situation == 'B'){takeAction(situation, planB);}}void main()//测试{strategy('A');//通过回调函数,在运行时传入不同的参数,将调用不同功能的函数,从而实现了策略的动态性strategy('B');}
其原理图如下所示:
更进一步:异步回调机制
以上几节所讲的回调机制,其实指的都是同步回调机制,同步的含义在于:Caller对Callee的调用,以及Callee对Caller.fun()的调用,只有在调用完成,即函数返回以后,调用方的程序才能够继续往下执行。这个时候,如果Callee的调用是一个很耗时的操作(如IO操作),则将严重影响Caller的执行,造成对Caller的阻塞。
于是,我们希望得到这样一种机制:Caller在告诉Callee必须完成Caller.fun()中的任务后,就可以不去管Callee啥时执行以及啥时完成的事情,而是可以继续执行Caller自身的任务。只有等到Callee完成任务,并通知了Caller后,Caller才回来对Callee的操作后的结果进行进一步的处理,这样的话,Caller就能够避免被阻塞,而不能保证有效响应时间的困扰。当然,要实现这种机制,首先需要满足以下两个要求:
1:这种机制只能是在多进程或多线程的情况下才能实现
2:Caller的之后执行的代码并不依赖于Callee的调用及其调用结果
满足了上述两个要求以后,我们就可以使用一种更高级的调用机制:异步调用机制来满足上述要求。
异步调用机制简述
异步调用在应用程序框架中具有广泛的应用,并且特指多线程情况下。它同Windows的消息循环机制,消息响应,消息队列,事件驱动机制以及设计模式中的观察者模式等都是紧密相关的。
- 回调机制深入剖析
- 回调机制深入剖析
- 回调机制深入剖析
- 回调机制深入剖析
- 深入剖析C#继承机制
- 深入剖析C#继承机制
- 深入剖析C#继承机制
- 深入剖析C#继承机制
- 深入剖析Android消息机制
- 深入剖析Android消息机制
- 深入剖析Android消息机制
- 深入剖析Android消息机制
- 深入剖析Android消息机制
- 深入剖析Android消息机制
- 深入剖析Android消息机制
- 深入剖析Android消息机制
- 深入剖析Tomcat会话机制
- 深入剖析 redis 事务机制
- 每天一个小算法 --- 排序
- DIV position属性
- Linux内核学习笔记之系统启动(三)
- 动态规划的背包问题
- Oracle 集合中的SET与IS A SET 、IS NOT A SET例子
- 回调机制深入剖析
- Eclipse : Maven search dependencies doen't work
- andriod-api翻译(二)--Services
- <c:forEach varStatus="status">中 varStatus的属性简介
- MySQL 体系架构 Oracle体系架构 PostgreSQL体系架构
- CrawlScript语言轻松实现网络爬虫——轻松爬取整站信息
- Tiled源码分析(三): Undo/Redo实现
- Principles of Continuous Integration
- windows下em启动问题