设计模式之美
王争
前 Google 工程师,《数据结构与算法之美》专栏作者
123425 人已学习
新⼈⾸单¥98
登录后,你可以任选6讲全文学习
课程目录
已完结/共 113 讲
设计模式与范式:行为型 (18讲)
设计模式之美
15
15
1.0x
00:00/00:00
登录|注册

59 | 模板模式(下):模板模式与Callback回调函数有何区别和联系?

JdbcTemplate源码
Java语言实例
回调函数传递
代码实现对比
应用场景对比
应用举例三:addShutdownHook()
应用举例二:setClickListener()
应用举例一:JdbcTemplate
原理解析
应用
实现
原理
课堂讨论
重点回顾
模板模式 VS 回调
Callback回调函数
模板模式
模板模式与Callback回调函数

该思维导图由 AI 生成,仅供参考

上一节课中,我们学习了模板模式的原理、实现和应用。它常用在框架开发中,通过提供功能扩展点,让框架用户在不修改框架源码的情况下,基于扩展点定制化框架的功能。除此之外,模板模式还可以起到代码复用的作用。
复用和扩展是模板模式的两大作用,实际上,还有另外一个技术概念,也能起到跟模板模式相同的作用,那就是回调(Callback)。今天我们今天就来看一下,回调的原理、实现和应用,以及它跟模板模式的区别和联系。
话不多说,让我们正式开始今天的学习吧!

回调的原理解析

相对于普通的函数调用来说,回调是一种双向调用关系。A 类事先注册某个函数 F 到 B 类,A 类在调用 B 类的 P 函数的时候,B 类反过来调用 A 类注册给它的 F 函数。这里的 F 函数就是“回调函数”。A 调用 B,B 反过来又调用 A,这种调用机制就叫作“回调”。
A 类如何将回调函数传递给 B 类呢?不同的编程语言,有不同的实现方法。C 语言可以使用函数指针,Java 则需要使用包裹了回调函数的类对象,我们简称为回调对象。这里我用 Java 语言举例说明一下。代码如下所示:
public interface ICallback {
void methodToCallback();
}
public class BClass {
public void process(ICallback callback) {
//...
callback.methodToCallback();
//...
}
}
public class AClass {
public static void main(String[] args) {
BClass b = new BClass();
b.process(new ICallback() { //回调对象
@Override
public void methodToCallback() {
System.out.println("Call back me.");
}
});
}
}
上面就是 Java 语言中回调的典型代码实现。从代码实现中,我们可以看出,回调跟模板模式一样,也具有复用和扩展的功能。除了回调函数之外,BClass 类的 process() 函数中的逻辑都可以复用。如果 ICallback、BClass 类是框架代码,AClass 是使用框架的客户端代码,我们可以通过 ICallback 定制 process() 函数,也就是说,框架因此具有了扩展的能力。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

回调函数和模板模式是常用的软件设计模式,它们都具有复用和扩展的功能。回调函数是一种双向调用关系,A类事先注册某个函数F到B类,A类在调用B类的P函数的时候,B类反过来调用A类注册给它的F函数。而模板模式则是通过提供功能扩展点,让框架用户在不修改框架源码的情况下,基于扩展点定制化框架的功能,同时也可以起到代码复用的作用。 回调函数和模板模式在实际应用中有着相似的功能,但也有一些区别。回调函数可以分为同步回调和异步回调,而模板模式则更注重于提供一个框架的基本结构,让用户根据需要进行扩展和定制。在实际应用中,回调函数常用于事件监听器的注册,比如在Android应用开发中给控件注册事件监听器,而模板模式常用于框架开发中,提供功能扩展点。 举例来说,Spring框架中的JdbcTemplate就是基于回调函数实现的,它通过回调的机制,将不变的执行流程抽离出来,放到模板方法中,将可变的部分设计成回调,由用户来定制。另外,在客户端开发中,给控件注册事件监听器也是一种回调的应用,比如在Android应用开发中给Button控件的点击事件注册监听器。 总的来说,回调函数和模板模式都是在软件设计中常用的技术手段,它们各自在不同的场景下发挥着重要的作用,帮助开发者实现代码复用和功能扩展。回调和模板模式的区别主要在于实现方式和应用场景,而它们都是为了实现代码复用和功能扩展而存在的重要设计模式。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《设计模式之美》
新⼈⾸单¥98
立即购买
登录 后留言

全部留言(90)

  • 最新
  • 精选
  • Java垒墙工程师
    回调的方式是不是打乱了系统调用的层次?相互依赖,依赖关系变得复杂

    作者回复: 有点,不过权衡利弊吧,没有绝对的完美。

    2020-08-25
    2
    1
  • 吴小智
    模板方法和回调应用场景是一致的,都是定义好算法骨架,并对外开放扩展点,符合开闭原则;两者的却别是代码的实现上不同,模板方法是通过继承来实现,是自己调用自己;回调是类之间的组合。
    2020-03-18
    1
    109
  • L!en6o
    曾经重构代码对这模板模式和callback就很疑惑。个人觉得callback更加灵活,适合算法逻辑较少的场景,实现一两个方法很舒服。比如Guava 的Futures.addCallback 回调 onSuccess onFailure方法。而模板模式适合更加复杂的场景,并且子类可以复用父类提供的方法,根据场景判断是否需要重写更加方便。
    2020-03-19
    4
    77
  • 小晏子
    callback和hook不是一个层面的东西,callback是程序设计方面的一种技术手段,是编程语言成面的东西,hook是通过这种技术手段实现的功能扩展点,其基本原理就是callback。比如windows api中提供的各种事件通知机制,其本身是windows开放给用户可以扩展自己想要的功能的扩展点,而实现这些功能的手段是callback。 只要编程语言支持传递函数作为参数,都可以支持callback设计,比如c,golang,javascript,python等。另外一些框架中提供的功能扩展点我们称之为hook,比如vue在其实例生命周期中提供的各种hook函数。
    2020-03-18
    2
    59
  • 剑八
    模板方法就是定义一个流程,每个流程结点可变的就是一个抽象spi,由不同实现去现。 解决的是一个复用与扩展问题。复用的是这个流程本身以及某些结点可以是默认实现。扩展的是有些结点是可以有不同实现的场景。 回调是一种交互方式,由调用者告诉被调用者:你做完后还要做一个事情,这个事情是什么。然后被调用者做完后就可以做这个指定的事情。回调倒不用强制和模板方法概念合在一起。
    2020-07-05
    5
    43
  • 柠檬C
    个人看法:模板模式关注点还是在类与对象上,通过继承与多态实现算法的扩展 回调关注点在方法上,虽然在java语言中不得不以匿名内部类的形式出现,但本质是将方法当做参数一样传递,有点函数式编程的意思了
    2020-03-19
    2
    19
  • pedro
    callback应该偏语言层面,hook偏业务层面,二者一个是概念,一个是具体的落地方式。
    2020-03-18
    2
    12
  • 写代码的
    虽然模板模式和回调很像,甚至和可以互相替换,但是为了让它们的功能和名称更契合,我觉得按照这样原则来使用这两种方法是不是会更好些:如果预留的扩展点必须实现,因为这些扩展点包含和这个类本身相关的关键功能性代码,不实现的话这个类就是个半成品,无法使用,那么使用模板模式,因为模板模式使用的抽象类可以在与语言层面强制这些扩展点必须被实现;如果预留的扩展点可以不实现,或者这些扩展点的实现逻辑甚至可以和这个类完全无关,那么就使用回调,,回调使用的组合关系恰好可以让类和扩展点的实现进行解耦,比如按钮上的事件回调,回调中的逻辑和按钮这个类本身的功能并没有什么关系,甚至回调可以传 null。
    2020-08-30
    2
    10
  • 辣么大
    什么是“回调 ”?A注册一个函数到B,B执行某个函数时,会调用A注册的这个函数。 我见过的应用一般完全结束(关闭,收尾等)时用hook,其他情况用callback或者on...listener。这种区别更多是语意上的,不是实现上的。
    2020-03-24
    1
    6
  • 前端西瓜哥
    Callback 是在一个方法的执行中,调用嵌入的其他方法的机制,能很好地起到代码复用和框架扩展的作用。在 JavaScript 中,因为函数可以直接作为另一个函数的参数,所以能经常看到回调函数的身影,比如定时器 setTimeout(callback, delay)、Ajax 请求成功或失败对应的回调函数等。不过如果滥用回调的话,会在某些场景下会因为嵌套过多导致回调地狱。 Hook 本质上也是回调,但它往往和一些场景性的行为绑定在一起。在浏览器环境中,我们可以通过 img.onload = func1 来让图片在加载完后执行函数 func1,某种意义上算是一种 Hook。此外在 js 的 vue 框架中,也提供了组件生命周期的 Hook,比如 beforeDestory 钩子函数会在组件即将被销毁前执行,常用于销毁一些当前组件才会用到的定时器。
    2020-03-19
    6
收起评论
显示
设置
留言
90
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部