什么是回调函数(CallBack)

我们先来看下维基百科的定义:

在计算机程序设计中,回调函数,或简称回调(call),是指通过函数参数传递到其它代码的,某一块可执行代码的引用。这一设计允许了底层代码调用在高层定义的子程序。

这种标准的定义,大多数时候说的都比较抽象,下面我们以实际生活中的例子来讲解到底什么是回调函数。

回调函数的用途十分广泛,在各种编程语言里面都有体现,有点类似Spring里面IOC(inversion of control=控制反转)的概念,本身是一个非常简单的概念,看下面的一个例子:

假设一个场景:

老师给学生布置了作业,学生收到作业后开始写作业,写完之后通知老师查看,老师查看之后就可以回家。

回调的概念,在这里面就体现的淋漓尽致,在这里面有两个角色,一个是老师,一个是学生。老师有两个动作,第一个是布置作业,第二个是查看作业。而学生有一个动作是做作业, 那么问题来了,老师并不知道学生何时才能做完作业,所以比较优雅的解决办法是等学生的通知,也就是学生做完之后告诉老师就可以。这就是典型的回调理念。

那么在编程中,该如何体现? 从上面的分析中,可以得出来回调模式是双方互通的,老师给学生布置作业,学生做完通知老师查看作业。 关于回调,这里面还分同步回调和异步回调两种模式:

同步模式:

如果老师在放学后,给学生布置作业,然后一直等待学生完成后,才能回家,那么这种方法就是同步模式。

异步模式:

如果老师在放学后,给学生布置作业,这个时候老师并不想等待学生完成,而是直接就回家了,但告诉学生,如果完成之后发短信通知自己查看。这种方式就是异步的回调模式。

回调模式为了不影响主任务执行,一般会设计成异步任务。下面我们看下在Java中,模拟上面举的例子实现一个简单的回调,包括同步和异步两种模式:

首先,回调的方法我们最好定义成一个接口,这样便于扩展:

/***
 *通过接口定义回调函数
 */
public interface CallBack {
    //检查作业属于老师的功能,但由学生触发,故称回调
    public void checkWork();
}

然后,我们定义老师的角色:

package design_pattern.callback.demo2;
public class Teacher implements CallBack {
    private Student student;
    public Teacher(Student student) {
        this.student = student;
    }
    /***
     *  给学生分配作业
     * @param isSync true=同步回调 false=异步回调
     * @throws InterruptedException
     */
    public void assignWork(boolean isSync) throws InterruptedException {
        System.out.println("老师分配作业完成....");
        if(isSync){
            student.doWrok(this);//同步通知做作业
        }else{
            student.asynDoWrok(this);//异步通知做作业
        }
        System.out.println("老师回家了....");
    }
    @Override
    public void checkWork() {
        System.out.println("老师收到通知并查看了学生的作业!");
    }
}

上面定义的是老师角色,有两个行为,一个是布置作业,一个是检查作业,布置作业里面,在布置作业里面,老师可以选择同步回调还是异步回调。

接着我们看下学生角色如何定义:

public class Student  {
    public void doWrok(CallBack callBack) throws InterruptedException {
        System.out.println("学生开始做作业.....");
        TimeUnit.SECONDS.sleep(3);
        System.out.println("学生完成作业了,通知老师查看");
        callBack.checkWork(); //通知老师查看作业
    }
    public void asynDoWrok(CallBack callBack) throws InterruptedException {
     //通过一个线程来异步的执行任务
     Runnable runnable= new Runnable(){
            @Override
            public void run() {
                System.out.println("学生开始做作业.....");
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("学生完成作业了,通知老师查看");
                callBack.checkWork();
            }
        };
     Thread thread=new Thread(runnable);
     thread.start();
    }
}

学生角色里面只有一个行为做作业,但这里我提供了两种模式,一个是同步,一个是异步。

最后,我们来测试下:

public class AppMain {
    public static void main(String[] args) throws InterruptedException {
        Student student=new Student();//学生角色
        System.out.println("\n===============同步模式================");
        Teacher teacher=new Teacher(student);//老师角色
        //同步回调模式,老师给学生布置作业,老师等学生完成之后才能回家
        teacher.assignWork(true);
        System.out.println("\n===============异步模式================");
        //异步回调模式,老师给学生布置作业,布置完成之后就可以回家,学生完成之后会通知老师查看。
        teacher.assignWork(false);
    }
}

执行结果如下:

===============同步模式================
老师分配作业完成....
学生开始做作业.....
学生完成作业了,通知老师查看
老师收到通知并查看了学生的作业!
老师回家了....
===============异步模式================
老师分配作业完成....
老师回家了....
学生开始做作业.....
学生完成作业了,通知老师查看
老师收到通知并查看了学生的作业!

对于同步和异步两种模式的结果,在上面的输出内容里面可以非常清晰的看出来区别,也体现回调的双通模式。老师角色持有了学生对象的引用,并告诉学生做作业,而同时学生角色,也持有老师角色的引用,可以在自己完成作业后,告诉老师查看作业。

总结:

回调模式,在生活中的例子非常常见,在编程中最常见的就是各种GUI编程里面的按钮点击什么的,通过回调可以将控制权转移,配合上异步模式,可以让系统设计的更加优雅。

原文发布于微信公众号 - 我是攻城师(woshigcs)

原文发表时间:2018-11-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏机器学习算法与Python学习

精选26个Python实用技巧,想秀技能先Get这份技术列表!

Python 虽然是脚本语言,但是因为其易学,迅速成为科学家的工具,从而积累了大量的工具库、架构,人工智能涉及大量的数据科学,用 Python 是很自然的事。磨...

1322
来自专栏小樱的经验随笔

CTF---Web入门第十题 Once More

Once More分值:10 来源: iFurySt 难度:易 参与人数:4782人 Get Flag:2123人 答题人数:2166人 解题通过率:98%...

2976
来自专栏程序猿DD

程序员你为什么这么累【续】:编码习惯-函数编写建议

之前系列文章里面完整的代码已经上github,地址在文章最后 傻瓜都能写出计算机可以读懂的代码,只有优秀的程序员才能写出人能读懂的代码! 在我看来,编写简单的函...

21210
来自专栏轮子工厂

如果你想学好Python,这几本书说不定可以帮助到你哦

702
来自专栏Python中文社区

用Python实现微信接口(三)

專 欄 ❈爱撒谎的男孩,Python中文社区专栏作者 博客:https://chenjiabing666.github.io ❈ 群消息 itchat 增加...

2978
来自专栏AI科技大本营的专栏

精选26个Python实用技巧,想秀技能先Get这份技术列表!

【导读】Python 虽然是脚本语言,但是因为其易学,迅速成为科学家的工具,从而积累了大量的工具库、架构,人工智能涉及大量的数据科学,用 Python 是很自然...

1395
来自专栏量子位

Jupyter Notebook的三大短板,都被这个新工具补齐了

在机器学习和数据科学领域,Jupyter已经家喻户晓。它把笔记、代码、图表、注释融合在一个交互式的笔记本里,还能添加各种扩展功能。可谓机器学习入门进阶研究之神器...

1942
来自专栏企鹅号快讯

实战:从Python分析17-18赛季NBA胜率超70%球队数据开始…

干货 观点 案例 资讯 我们 ? 撸主: Casey 岂安业务风险分析师 主要负责岂安科技RED.Q的数据分析和运营工作。 就在昨天,12月19日,科比再...

2487
来自专栏BeJavaGod

BeJavaGod - 如何正确使用数据字典进行分类统一操作(一)

先说说什么是数据字典,这个玩意一般不太会解释,举个栗子吧~ 每个系统都会有用户表,性别:男(1)女(0) 另外我们做物流的会涉及到车型:卡车(1),轿车(2),...

3377
来自专栏liulun

Nim教程【一】

这应该是国内第一个关于Nim入门的系列教程 什么是Nim 我们先来引述网友 Luikore的一段话: Nim 不是函数式的, 但 ...

3439

扫码关注云+社区