当前位置: 首页 > news >正文

从 Interface 到 Lambda:一次串起 Java 和 Kotlin 的回调设计

引言

最近在写自己的日志库。

设计网络模块和日志模块解耦的时候,遇到了一个很自然的问题:

网络请求完成后,怎么通知日志模块?

第一反应很简单:

定义一个 Interface。

interface NetworkEventListener { fun onNetworkEvent(event: NetworkLogEvent) }

网络模块产生事件:

listener?.onNetworkEvent(event)

日志模块决定怎么处理。

写到这里,突然想到:

Kotlin 不是有 Lambda 和高阶函数吗?

是不是也可以这样?

var callback: ((NetworkLogEvent) -> Unit)? = null callback?.invoke(event)

好像也完全没问题。

继续往下想:

Interface、Listener、Callback、匿名内部类、Lambda、高阶函数、invoke……

突然发现,这些年学过的很多东西,看起来完全不同,但实际上一直在解决同一个问题。

那就是:

如何把一段行为交给别人,并在合适的时候执行。

于是,我试着从 Interface 开始,把 Java 和 Kotlin 的这条回调设计路线重新串了一遍。


一、最开始:Interface

刚学 Java 时,大概都写过这样的代码:

interface Animal{ void eat(); } class Dog implements Animal{ @Override public void eat(){ System.out.println("eat"); } }

老师会告诉我们:

  • 抽象;

  • 多态;

  • 面向接口编程。

工作以后,又会写很多这样的接口:

interface LogUploader{ fun upload(logs: List<Log>) }

或者:

interface Cache{ fun save() fun load() }

这些接口表达的是:

我需要一种能力。

例如:

logUploader.upload(logs)

意思就是:

请你帮我上传日志。

Cache:

cache.save()

意思就是:

请你帮我缓存数据。

这是我们最熟悉的 Interface。


二、另一种 Interface:事件通知

最近写日志库的时候,又定义了一个接口:

interface NetworkEventListener{ fun onNetworkEvent(event: NetworkLogEvent) }

这个接口和 LogUploader 有什么区别?

仔细想想:

LogUploader:

请你帮我做一件事情。

NetworkEventListener:

我通知你发生了一件事情。

例如:

listener?.onNetworkEvent(event)

表示:

网络请求完成了。

通知外部。

Android 到处都是这种接口:

OnClickListener TextWatcher LocationListener SensorEventListener

例如:

button.setOnClickListener(...)

Button 并不是说:

请你帮我点击。

而是在说:

我被点击了。

通知你一下。

原来:

Interface 不仅可以表达能力。

也可以表达事件。

而这两种场景,我以前都会写,却一直没有放在一起理解。


三、Java 是怎么做回调的?

为了理解这件事情,我们先看看最传统的 Java 回调。

定义接口:

public interface NetworkEventListener { void onNetworkEvent(NetworkLogEvent event); }

网络模块:

public class NetworkClient { private NetworkEventListener listener; public void setNetworkEventListener( NetworkEventListener listener ){ this.listener = listener; } public void request(){ NetworkLogEvent event = new NetworkLogEvent( "/login", 200, 120 ); if(listener != null){ listener.onNetworkEvent(event); } } }

外部:

networkClient.setNetworkEventListener( new NetworkEventListener() { @Override public void onNetworkEvent( NetworkLogEvent event ) { logger.write(event); } } );

仔细看。

其实就是:

定义 Interface。

传进去。

以后某个时机执行。

这就是 Callback。


四、Kotlin 的 Interface 回调

Kotlin 写法更简单:

interface NetworkEventListener{ fun onNetworkEvent( event: NetworkLogEvent ) }

网络模块:

class NetworkClient{ var listener: NetworkEventListener? = null fun request(){ val event = NetworkLogEvent( "/login", 200, 120 ) listener?.onNetworkEvent(event) } }

使用:

networkClient.listener = object : NetworkEventListener{ override fun onNetworkEvent( event: NetworkLogEvent ) { logger.write(event) } }

虽然 Kotlin 语法简单了。

但是本质没有变化。

还是:

Interface。

Callback。

事件通知。


五、Lambda 和高阶函数

写到这里,突然想到:

Kotlin 不是可以直接这样吗?

网络模块:

class NetworkClient{ var onNetworkEvent: ((NetworkLogEvent)->Unit)? = null fun request(){ val event = NetworkLogEvent( "/login", 200, 120 ) onNetworkEvent?.invoke(event) } }

使用:

networkClient.onNetworkEvent = { event -> logger.write(event) }

突然发现:

Interface:

listener?.onNetworkEvent(event)

高阶函数:

onNetworkEvent?.invoke(event)

看起来已经很接近了。

本质上都是:

把一段逻辑交给别人。

以后再执行。


六、Interface 和高阶函数怎么选?

如果只有一个回调:

例如:

网络请求完成。

扫码成功。

登录成功。

高阶函数非常舒服:

var onSuccess: ((User)->Unit)? = null

但是:

如果事件越来越多:

interface NetworkEventListener{ fun onRequestStart() fun onRequestSuccess() fun onRequestFailed() fun onRequestFinished() }

会更加清晰。

如果全部用高阶函数:

class NetworkClient( val onStart:(()->Unit)?, val onSuccess: ((NetworkLogEvent)->Unit)?, val onFailed: ((Throwable)->Unit)?, val onFinished: (()->Unit)? )

当然也能写。

但是组织性不如 Interface。

所以:

高阶函数并不是取代 Interface。

而是在单回调场景下,把 Interface 写得更轻量。


七、最近写库最大的收获

最近设计日志库:

网络模块产生事件。

日志模块消费事件。

第一反应:

定义 Interface。

后来想到:

是不是可以用高阶函数?

继续想:

Listener。

Callback。

匿名内部类。

Lambda。

invoke。

突然发现:

以前总觉得:

Interface 是 Interface。

Listener 是 Listener。

Callback 是 Callback。

Lambda 是 Lambda。

高阶函数是高阶函数。

最近做项目的时候,才发现它们之间一直都有联系。

虽然语法不同。

虽然时代不同。

虽然 Java 和 Kotlin 的写法不同。

但是很多时候,它们都在解决同一个问题。

如何把一段行为交给别人,并在未来某个时机执行。


总结

最近写日志库,最大的收获并不是把日志框架写出来了。

而是突然发现:

这些年学过的:

  • Interface;

  • Listener;

  • Callback;

  • 匿名内部类;

  • Lambda;

  • 高阶函数;

  • invoke。

并不是一堆零散的知识。

它们一直都在那里,只是以不同的形式出现。

以前学 Java,学的是 Interface。

后来做 Android,学的是 Listener。

再后来学 Kotlin,学的是 Lambda 和高阶函数。

直到最近设计自己的库,才发现:

Interface 可以暴露能力:

logUploader.upload(logs)

也可以通知事件:

listener.onNetworkEvent(event)

高阶函数:

callback.invoke(event)

只是另一种更加轻量的回调形式。

它们虽然写法不同,但很多时候都在完成同一件事情:

把一段行为交给别人,并在合适的时候执行。

或许,对于一个程序员来说,

从「会写这些代码」,

到「知道它们为什么这样设计」,

本身就是成长的一部分。

http://www.jsqmd.com/news/1022622/

相关文章:

  • 2026甘南贵金属旧料回收优质实体店精选 5 家 黄金回收铂金白银回收真实探店测评清单 - 中业金奢再生回收中心
  • ContextMenuManager深度解析:如何安全高效管理Windows右键菜单
  • 2026年门窗配套材料供应链优化|长沙硅酮胶代理商与高端五金品牌深度横评 - 企业名录优选推荐
  • 2026吉安贵金属旧料回收优质实体店精选 5 家 黄金回收铂金白银回收真实探店测评清单 - 中业金奢再生回收中心
  • 全国优质共模电感专业厂家推荐,布局广东广州等地区,德鸿感应赋能高端电子产业更靠谱 - 十大品牌榜
  • 腾讯发布WorkBuddy企业版,员工能力或成企业资产(含限时福利)
  • 2026 杭州黄金回收 “天花板”|零差评+免费估价+全城上门 - 开心测评
  • 跨境投资合规操作指南:从政策理解到实操落地
  • Llama3、Qwen2、Mistral开源大模型选型实战指南
  • 二项式反演:从“至少”到“恰好”的组合计数利器
  • 2026大连贵金属旧料回收优质实体店精选 5 家 黄金回收铂金白银回收真实探店测评清单 - 中业金奢再生回收中心
  • 媞娜团队:持国际旅行社资质的新疆正规旅行社如何做纯玩闺蜜小团 - 老张爱旅游
  • 2000-2024年地级市农业绿色全要素生产率GTFP
  • 手机号被运营商回收并分配给另一个人,用户会员数据如何处理?
  • 全媒体广告投放如何量化ROI?一套跨平台归因模型详解
  • 免费微信投票小程序推荐 | 云众评选VS腾讯投票VS问卷星,免费无广告防刷 + 图文视频谁更强? - 微信投票小程序
  • 图片去水印用什么工具?2026电脑手机免费去水印软件排行
  • 扩散语言模型原理与工程实践详解
  • 轮胎撕碎机单机选型参考:从刀盘到产能的那些细节 - 深度智识库
  • 2026金昌本地认可的 5 家排污许可废气废水监测机构实地测评汇总 废水废气 + 自行监测 + CMA 检测报告 附电话地址 - 科信检测
  • 大模型时代工程师的不可替代性:从执行者到系统定义者
  • 2026枣庄商户高频选择的 5 家公共卫生第三方检测机构实地测评整理 公共场所 + 水质卫生检测 附电话地址 - 鉴安检测
  • R3nzSkin完整指南:5分钟掌握英雄联盟安全换肤技术
  • 2026沧州本地认可的 5 家排污许可废气废水监测机构实地测评汇总 废水废气 + 自行监测 + CMA 检测报告 附电话地址 - 科信检测
  • 对话式AI赛道全景:从大模型到智能体的范式跃迁与核心玩家解析
  • 2026西双版纳当地贵金属回收权威名录 TOP5 黄金金条铂金白银回收线下门店信息汇总 - 信誉隆金银铂奢回收
  • 2026年9月PMP倒计时:看完这篇再决定要不要考,别再走弯路了
  • 上海羁押必要性审查申请:降低羁押率的法律途径与材料准备 - 品牌2026
  • 2026漳州当地贵金属回收权威名录 TOP5 黄金金条铂金白银回收线下门店信息汇总 - 信誉隆金银铂奢回收
  • 星际长丝结构与恒星形成的动力学研究