编程基础知识——C/C++,Java,ObjC的回调方式探讨

来源:互联网 发布:海岛研究所数据大全 编辑:程序博客网 时间:2024/06/05 05:45

什么是回调?

因为本人是从C开始步入编程世界的,很多术语改不过口,叫习惯了。java里通常叫listener(监听器),C/C++里通常叫callback(回调),ObjC里面叫delegate(委托)

回调就是调用事先设置一个上下文数据(它可能是某个消息值,可能是某个函数,可能是某个对象)到某个负责处理数据的对象或者代码里。然后开始执行这个处理过程,这个处理过程处理完了之后,会根据处理的结果将之前设置的对应的上下文数据反馈给你。

举个例子吧,比如我有个函数是下载一个http的图片资源。在调用这个函数之前,我先告诉这个函数,如果下载成功了,你就给我发一个通知1,如果失败了,就给我发一个通知0(当然是返回01最简单啦,但是如果是异步的呢)。回调的形态多种多样,各种方式的都有,但是本质上就是一个模块的代码通知告知另一个模块某个结果,某个状态,某个进度。

C语言里面,由于只有函数,没有对象。所以C语言的回调常用两种:1、消息通知,2、回调函数。

对于消息通知来说,需要一个消息循环。当进入某个状态或者处理完某个人物的时候,发送一个通知到消息循环,在负责处理的地方,等待这个消息就可以了。

实际开发中用到消息循环的地方有:win32API/MFC 的消息机制,androidhandler机制,都是消息回调方式。

对于函数回调来说,执行A函数的时候,函数参数里传入S函数和F函数的指针,如果A执行成功了,最后在A里面调用S,如果A执行失败了,在最后A里面调用F

比如C里面的回调大概就是下面这样的。

void S(){}void F(){}typedef (void*)() callback ;void A(callback s, callback f){if(成功)s();elsef();}



C进化到C++之后,回调的方式就好多了,因为有对象了。管理对象总是比管理单个函数方便的多,因为对象可以同时关联函数和数据。

比如C++ 对象方式的回调样子大概像下面这样


struct CPPCallback{virtual void callbackFunctionS();virtual void callbackFunctionF();}void A(CPPCallback* calback){if(成功)calback-> callbackFunctionS();elsecalback-> callbackFunctionF();}


使用对象指针回调会方便很多,因为CPPCallback通常是纯虚类,由实际场景中的某个类来实现。并且对象指针回调更加符合面向对象的模式,越是高级的语言,越面向对象,如果和这个趋势相违背,那势必用起来是不那么方便的。C++同时也可以使用C的回调方式,就不在举例了。


java的回调方式,是按照 触发器 +监听器的理念设计的。本质和C++那个没什么区别,叫法不一样。


interface JavaListener{public void callbackFunctionS();public void callbackFunctionF();}void A(JavaListener listener){if(成功)listener.callbackFunctionS();elselistener.callbackFunctionF();}


java官方的代码以及开源代码里面,一般出现的都是这种回调方式(android handler那种除外),java完全面向对象所以不会出现单独的函数回调。


监听器 + 触发器的叫法,我个人是非常喜欢的。以至于个人在开发 C++代码,ObjC代码,其他所有语言的程序的时候,都沿用了Java里面的叫法,特别是ObjC的委托授权叫法,实在是拗口,不好理解。


ObjC的回调方式,官方的叫法叫委托(delegate),但是ObjC的回调的具体形式却很灵活,由于ObjC也面向对象,所以它肯定可以支持java这种回调。

但是ObjC还支持一种 对象指针 +函数名的轻量级回调,后者在代码书写量上面,反而要简单许多。


比如ObjC中类似java的那种回调方式

@protocol XXXXDelegate <NSObject>-(void) callbackFunctionS;-(void) callbackFunctionF;@end-(void)A:(id<XXXXDelegate>)delegate{if(成功)[delegate callbackFunctionS];else[delegate callbackFunctionF];}




ObjC第二种更简单的回调,第二种回调不用定义protocol


@class-implemention SomeClassA //假设某个类的实现文件-(void) callbackFunctionS{}-(void) callbackFunctionF{}-(void)A:(id)delegate withS:(SEL)funS withF:(SEL)funF{if(成功)[delegate performSelector:funS withObject:nil]; else[delegate performSelector:funF withObject:nil]; }-(void)callA //演示调用A的情况{[self A:self withS:@selector(callbackFunctionS) withF:@selector(callbackFunctionF)];}@end



只要调用A第一个参数传入的对象 delegate的类里面有名字叫callbackFunctionS和叫callbackFunctionF的函数即可。

ObjC的类型 SEL,实际上就是一个 char*类型,它的原理是通过字符串去查找某个函数,然后再某个对象上执行这个函数。




基本的这三种语言的回调方式就是这样的了,如果取长补短,其他语言借鉴一下思路,java语言里也可以实现ObjC的第二种回调方式。

C++则比较麻烦,因为C++不直接支持反射,只能通过类似微软的COM模式,模拟实现。微软的COM也是个不错的东西,火狐浏览器的底层架构,就是用的XPCOM(基于COM思路设计的)。


C++如何反射,可以参考我的另一篇文章。


java的反射机制,比ObjC更彻底,因为java是纯解释性语言,ObjC是半解释语言。所以java实现ObjC第二种回调方式,so easy


完整代码如下:


package com;import java.lang.reflect.Method;public class Main2 {public static void main(String[] args) throws Exception{new Main2().run(); }public void callbackFunctionS() {System.out.println("callbackFunctionS");}public void callbackFunctionF() {System.out.println("callbackFunctionF");}public void A(Object obj, String funcS, String funcF) throws Exception{Class clz = obj.getClass() ;Method methodS = clz.getMethod(funcS, null);Method methodF = clz.getMethod(funcF, null); if(true) //成功methodS.invoke(obj, null);elsemethodF.invoke(obj, null);}public void run() throws Exception{ this.A(this, "callbackFunctionS", "callbackFunctionF");}}



不同语言,不同平台,本质上都是一样的。好的思维模式,设计理念都可以借鉴。


0 0
原创粉丝点击