CALLBACK(委托)的实现模式

最基本的回调函数就是把函数指针做为参数传入。 如函数A做为参数传入函数B,由B函数决定何时何地调用函数A

例如:

A() { ... do something and return some value ... }
B(A)
{

     ... do something first ...

     A()     //CALLBACK

     ... do something later ...

}

使用场景:

通常情况是在函数B()中做一些事情,然后发现需要别人帮它完成一些事情来进行下一步的工作,这时候就去调用一个CALLBACK函数A(),函数A()在其他地方完成了该动作以后再返回给函数B()通知事件完成了。然后B就可以接下来完成自己接下来的工作了。

 

曾经在CSDN看到过一个很形象的比喻:

你饿了,想吃饭,就每隔一会儿去问你妈一声"开饭没有啊?"这就正常函数调用.
但是今天你妈包饺子,花的时间比较长,你跑啊跑啊,就烦了.于是你给你妈说,我先出去玩会,开饭的时候打我手机.等过了一阵,你妈给你打电话说"开饭啦, 快回来吃饭吧!" 其中,你告诉你妈打手机来叫你,就是一个你把回调函数句柄保存注册到你妈那里的动作.你妈打电话叫你,就是个回调过程.

那么按照上面这个例子,儿子就是B,妈妈就是A。 因为儿子要实现吃饭,就需要妈妈帮自己实现烧饭以及通知自己饭烧好了的过程。儿子把饭烧好了打电话给自己(即回调函数)注册到了妈妈那里,妈妈做菜途中发现完成了,就会回调给儿子,儿子接到电话以后就回家吃饭,然后吃完以后还有可能再返回一些数据给妈妈(比如称赞饺子好吃..)

 

 

接下来让我们用代码模拟实现一下这个比喻来帮助加深理解回调的概念

 

首先,让我先来看看不使用回调 的实现代码

#include <iostream>
#include <string>
using namespace std;


class Child
{
private:
    string name;
public:
    Child(const string name) { this->name = name; cout<<"child's name:"<<this->name<<endl; }
    string getChildName(){ return this->name; }
    void play() { cout<<this->name<<" is playing outside ..."<<endl; }
    void call(){ cout<<this->name<<" is getting mum's call and going back to home"<<endl; this->eat(); }
    void eat() {
        cout<<this->name<<" start to eat"<<endl;
        cout<<this->name<<" comments on the food: so yummy!!!"<<endl;
    }
};

class Mum
{
private:
    Child* childRegistered;
public:
    void registerChild(Child* child){
        childRegistered = child;
        cout<<"Register "<<childRegistered->getChildName()<<" with mum's cooking notification"<<endl;
    }
    void cooking(){ cout<<"mum is cooking ..." <<endl; }
    void finishCooking(){ cout<<"mum finished cooking and start to call yshen!"<<endl; childRegistered->call(); }
};

int main()
{
    Mum* mum = new Mum();
    Child* child = new Child("yshen");
    mum->registerChild(child);
    mum->cooking();
    child->play();
    mum->finishCooking();
    delete mum;
    delete child;
    system("PAUSE");
    return 0;
}

 

------------ output ---------------

child's name:yshen
Register yshen with mum's cooking notification
mum is cooking ...
yshen is playing outside ...
mum finished cooking and start to call yshen!
yshen is getting mum's call and going back to home
yshen start to eat
yshen comments on the food: so yummy!!!

------------------------------------

分析:在如上的代码中各个类实现各自的逻辑,Mum类负责烧饺子以及通知儿子饭烧好了,Child类负责在妈妈那里注册自己想吃饭以及接收妈妈的通知相应事件。而在main()函数中(第三方)则拥有对整个业务逻辑的控制权。而我们希望达到的是,不需要第三方的控制存在,因为儿子吃饭,妈妈做饭,这整个流程和其他业务完全无关。儿子类和妈妈类完全可以互相通讯完成整个事件。

 

 


 

 

 

 

修改如下,使用回调的方式实现,儿子在妈妈处注册自己想吃饭,妈妈做好以后调用回调函数接口通知儿子。

#include <iostream>
#include <string>
using namespace std;

class CallMeEventListener     // CALLBACK interface
{
public:
    virtual void notifyEventHandler() = 0;
};

class Mum
{
private:
    CallMeEventListener* callback;
public:
    void registerCallback(CallMeEventListener* callback)     //重要: 用接口对象而非Child对象 ,实现封装
    {
        this->callback = callback;
        cout<<"Registered with mum's cooking notification"<<endl;
    }
    void cooking()
    {
        for(int i=0;i<5;i++)
        {
            cout<<"mum is cooking ..."<<endl;
        }
        cout<<"mum finished cooking and start to call yshen!"<<endl;
        this->callback->notifyEventHandler();    //完成cooking以后回调通知Child
    }
};

class Child : public CallMeEventListener
{
private:
    string name;
public:
    Child(const string name) { this->name = name; cout<<"child's name:"<<this->name<<endl; }
    string getChildName(){ return this->name; }
    void eat(Mum* mum)     //主要业务逻辑,先在Mum类中注册自己,然后自己完成一些事情(play), 再通知Mum开始做饭
    {
        mum->registerCallback(this);
        this->play();
        mum->cooking();
    }
    void play() { cout<<this->name<<" is playing outside ..."<<endl; }
    void notifyEventHandler()
    {
        cout<< this->name <<" is getting mum's call, going back to home and start to eat"<<endl;
        cout<< this->name <<" comments on the food: so yummy!!!"<<endl;
    }
};

int main()
{
    Mum* mum = new Mum();
    Child* child = new Child("yshen");
    child->eat(mum);   //这仅仅一个函数处理了所有的业务逻辑,并相互通信的实现细节被封装了起来
    delete mum;
    delete child;
    return 0;
}

------------ output ---------------

child's name:yshen
Registered with mum's cooking notification
yshen is playing outside ...
mum is cooking ...
mum is cooking ...
mum is cooking ...
mum is cooking ...
mum is cooking ...
mum finished cooking and start to call yshen!
yshen is getting mum's call, going back to home and start to eat
yshen comments on the food: so yummy!!!

------------------------------------

分析:

程序的目标就是完成儿子的吃饭 child->eat(mum) ,其中用一个妈妈对象作为eat()的参数,因为在mum中实现了回调过程。 我们可以把整个实现过程可以分解为如下步骤。

1. 儿子告诉妈妈要吃饭,把自己(this)注册到妈妈那里 mum->registerCallback(this);

2. 儿子自己完成一些事情,比如this->play();

3. 妈妈去做饭 mum->cooking();

由于儿子已经在妈妈那里注册过想吃饭了,所以当妈妈烧好饭以后,知道要打电话Notify已经注册过该服务的那个儿子,这就实现了一个回调过程。 儿子只要和妈妈注册一下,然后就等妈妈做饭,妈妈做好饭以后就会以类似Event Notify的方式callback给儿子。

 

 


 

 

 

 

 

另外附上对应的Java代码实现

interface CallMeEventListener {       // CALLBACK interface
    public void notifyEventHandler();
}

class Child implements CallMeEventListener {
    private String name;
    Child(String name) {
        this.name = name;
        System.out.println("child's name:" + this.name);
    }
    public String getChildName() {
        return this.name;
    }
    public void eat(Mum mum) {
        mum.registerCallback(this);    //first register him with mum
        this.play();     // do some own stuff ....
        mum.cooking();  //let mum to do the cooking and notify him once finished
    }
    public void play() {
        System.out.println(this.name + " is playing outside ...");
    }
    public void notifyEventHandler() {
        System.out.println(this.name + " is getting mum's call, going back to home and start to eat");
        System.out.println(this.name + " comments on the food: so yummy!!!");
    }
}

class Mum {
    private CallMeEventListener callback;
    public void cooking() {
        for(int i=0;i<10;i++) {
            System.out.println("mum is cooking ...");
        }
        System.out.println("mum finished cooking and start to call yshen!");
        this.callback.notifyEventHandler();    // CALLBACK
    }
    public void registerCallback(CallMeEventListener callback) {
        this.callback = callback;
        System.out.println("Registered with mum's cooking notification");
    }
}

public class CallBackTest {
    public static void main(String[] args) {
        Mum mum = new Mum();
        Child child = new Child("yshen");
        child.eat(mum);
    }
}

 

 

 

 

 

 

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、 4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.m或d论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 、1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。、资源 5来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。、资 5源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值