科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件异步消息的传递之回调机制

异步消息的传递之回调机制

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用

作者:陈家朋 来源:yesky 2007年10月28日

关键字: Linux

  • 评论
  • 分享微博
  • 分享邮件
 2.3 应用举例

  C语言的标准库函数中很多地方就采用了回调函数来让用户定制处理过程。如常用的快速排序函数、二分搜索函数等。

  快速排序函数原型:

void qsort(void *base, size_t nelem, size_t width, int (_USERENTRY *fcmp)(const void *, const void *));

  二分搜索函数原型:

void *bsearch(const void *key, const void *base, size_t nelem, size_t width, int (_USERENTRY *fcmp)(const void *, const void *));

  其中fcmp就是一个回调函数的变量。

  下面给出一个具体的例子:

#include <stdio.h>
#include <stdlib.h>

int sort_function( const void *a, const void *b);
int list[5] = { 54, 21, 11, 67, 22 };

int main(void)
{
 int x;

 qsort((void *)list, 5, sizeof(list[0]), sort_function);
 for (x = 0; x < 5; x++)
  printf("%i\n", list[x]);
  return 0;
}

int sort_function( const void *a, const void *b)
{
 return *(int*)a-*(int*)b;
}

  2.4 面向对象语言中的回调(Delphi)

  Dephi与C++一样,为了保持与过程语言Pascal的兼容性,它在引入面向对象机制的同时,保留了以前的结构化特性。因此,对回调的实现,也有两种截然不同的模式,一种是结构化的函数回调模式,一种是面向对象的接口模式。

  2.4.1 回调函数

  回调函数类型定义:

type
TCalcFunc=function (a:integer;b:integer):integer;

  按照回调函数的格式自定义函数的实现,如

function Add(a:integer;b:integer):integer
begin
 result:=a+b;
end;
function Sub(a:integer;b:integer):integer
begin
 result:=a-b;
end;

  回调的使用

function Calc(calc:TcalcFunc;a:integer;b:integer):integer

  下面,我们就可以在我们的程序里按照需要调用这两个函数了

c:=calc(add,a,b);//c=a+b
c:=calc(sub,a,b);//c=a-b

  2.4.2 回调对象

  什么叫回调对象呢,它具体用在哪些场合?首先,让我们把它与回调函数对比一下,回调函数是一个定义了函数的原型,函数体则交由第三方来实现的一种动态应用模式。要实现一个回调函数,我们必须明确知道几点:该函数需要那些参数,返回什么类型的值。同样,一个回调对象也是一个定义了对象接口,但是没有具体实现的抽象类(即接口)。要实现一个回调对象,我们必须知道:它需要实现哪些方法,每个方法中有哪些参数,该方法需要放回什么值。

  因此,在回调对象这种应用模式中,我们会用到接口。接口可以理解成一个定义好了但是没有实现的类,它只能通过继承的方式被别的类实现。Delphi中的接口和COM接口类似,所有的接口都继承与IInterface(等同于IUnknow),并且要实现三个基本的方法QueryInterface, _AddRef, 和_Release。

  定义一个接口

type IShape=interface(IInterface)
procedure Draw;
end

  实现回调类

type TRect=class(TObject,IShape)
protected
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
procedure Draw;
end;

type TRound=class(TObject,IShape)
protected
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
procedure Draw;
end;

  使用回调对象

procedure MyDraw(shape:IShape);
var
shape:IShape;
begin
shape.Draw;
end;

  如果传入的对象为TRect,那么画矩形;如果为TRound,那么就为圆形。用户也可以按照自己的意图来实现IShape接口,画出自己的图形:

MyDraw(Trect.Create);
MyDraw(Tround.Create);

  2.4.3 回调方法

  回调方法(Callback Method)可以看作是回调对象的一部分,Delphi对windows消息的封装就采用了回调方法这个概念。在有些场合,我们不需要按照给定的要求实现整个对象,而只要实现其中的一个方法就可以了,这是我们就会用到回调方法。

  回调方法的定义如下:

TNotifyEvent = procedure(Sender: TObject) of object;
TMyEvent=procedure(Sender:Tobject;EventId:Integer) of object;

  TNotifyEvent 是Delphi中最常用的回调方法,窗体、控件的很多事件,如单击事件、关闭事件等都是采用了TnotifyEvent。回调方法的变量一般通过事件属性的方式来定义,如TCustomForm的创建事件的定义:

property OnCreate: TNotifyEvent read FOnCreate write FOnCreate stored IsForm;

  我们通过给事件属性变量赋值就可以定制事件处理器。

  用户定义对象(包含回调方法的对象):

type TCallback=Class
procedure ClickFunc(sender:TObject);
end;
procedure Tcallback.ClickFunc(sender:TObject);
begin
showmessage('the caller is clicked!');
end;

  窗体对象:

type TCustomFrm=class(TForm)
public
procedure RegisterClickFunc(cb:procedure(sender:Tobject) of object);
end;

procedure TcustomFrm..RegisterClickFunc(cb:TNotifyEvent);
begin
self.OnClick=cb;
end;

  使用方法:

var
frm:TcustomFrm;
begin
frm:=TcustomFrm.Create(Application);
frm.RegisterClickFunc(Tcallback.Create().ClickFunc);
end;
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章