在一个应用系统中,不论使用何种编程语言,模块之间要进行调用,仅存在三种方式:同步调用、异步调用、回调。本文就其中回调方式进行详细解读,并通过匿名内部类的手段,在最后实现一个同步回调的过程。

一、回调的意义

在学习回调之前,我们需要知道使用回调的原因,和回调的应用场景。

不如先思考两个问题:

  1. 栈底对栈顶通常是不可见的,但是栈顶有时需要直接调用栈底
  2. 上级派下级做事,在此期间,下级可能需要通过上级获取高权限的协助

而在本例中,回调方式被用来处理爬取后的大量返回数据。在业务层面,这些数据被安排在调用方进行处理,但是调用方却没有处理这些数据的足够权限。于是,通过回调,业务被很好的分层并且执行。

二、如何实现同步回调

本文对同步回调的业务需求如下:

  1. 回调方调用调用方进行数据爬取
  2. 调用方调用回调方进行数据存储
  3. 调用方调用回调方进行日志记录

根据需求可以得到回调过程的时序图:

相应代码如下:

public interface Handler {
void handle(String info);
} public class Task {
private String info; private void setInfo(String info) {
this.info = info;
} public void call() {
Crawler.getInstance().crawl(new Handler() {
@Override
public void handle(String info) {
setInfo(info);
}
});
}
} public class Crawler {
private static Crawler instance = null; public static Crawler getInstance() {
if (instance == null) {
instance = new Crawler();
}
return instance;
} private String getInfo() {
return "the info from crawler";
} public void crawl(Handler handler) {
handler.handle(getInfo());
}
}

三、遇到的问题

如果我们使用代码来实现上述回调过程,不难会发现这样一个问题:Task调用Crawler,Crawler调用Handler,Hanlder调用Task。很明显,此处存在一个环,产生了循环依赖的问题,而接口可以为我们提供良好的解决方案。

四、为什么通过匿名内部类的方式

用 Java 实现同步回调有许多方式,为什么我们要通过匿名内部类的方式来实现回调,直接回调不香吗?

不妨先看看直接回调的顺序图:

相应代码如下:

public interface Handler {
void handle(String info);
} public class Task implements Handler{
private String info; private void setInfo(String info) {
this.info = info;
} public void call() {
Crawler.getInstance().crawl(this);
} @Override
public void handle(String info) {
setInfo(info);
}
} public class Crawler {
private static Crawler instance = null; public static Crawler getInstance() {
if (instance == null) {
instance = new Crawler();
}
return instance;
} private String getInfo() {
return "the info from crawler";
} public void crawl(Handler handler) {
handler.handle(getInfo());
}
}

直接回调带来的最大问题便是回调接口的暴露,也就是说回调接口不一定用于回调,也可以用于直接访问。这在业务层面的设计上是绝对不允许的,而匿名内部类在执行回调等特定业务的同时,可以很好的对外隐藏用于回调的接口。

五、总结

常规类通常无法对回调等特定接口作出限定,要么都可以访问,要么都拒绝访问。而内部类通过牺牲自身的被访问权限,提升了自身访问外部类的能力,这使得其成为实现回调的首选方案。在JAVA8中,lambda表达式本质上就是匿名内部类的语法糖。

注:匿名内部类本质上是成员内部类、局部内部类的简化写法,这里将其统称为内部类。

参考链接

[1] <<Java核心技术>> 卷一

[2] https://www.cnblogs.com/xrq730/p/6424471.html

[3] https://www.cnblogs.com/heshuchao/p/5376298.html

[4] https://www.cnblogs.com/dolphin0520/p/3811445.html

最新文章

  1. 项目:BluetoothChat
  2. ASP.NET MVC3系列页面缓存、缓存依赖SQL(真实项目注意细节)
  3. poj2749
  4. pig中使用的一些实例语法
  5. 项目中的导出(jxl插件)
  6. python学习之路网络编程篇(第五篇)
  7. SAP MM 巴西采购订单中的NCM Code
  8. TerminateProcess实现关闭任意程序
  9. 浏览器输入URL按回车后都经历了什么?
  10. 基于python的发送邮件案例
  11. (百度)centos7上安装apache指南
  12. Linux下清空或删除大文件内容的2种方法
  13. git之win安装git和环境配置及常用命令总结
  14. angularjs路由传递参数
  15. 审核被拒绝。附近??Guideline 5.1.2
  16. Java(16-19)
  17. MYSQL-不能创建表
  18. android矩阵具体解释
  19. pxc wsrep_sst_method均配置为xtrabackup-v2报错
  20. mysql驱动jar包下载

热门文章

  1. 面试官:分库分表之后,id 主键如何处理?
  2. spring aop原理和实现
  3. 静态代理、jdk动态代理、cglib动态代理
  4. python-生成器(generation)
  5. python os模块方法详解
  6. PHP正则表达式核心技术完全详解 第2节
  7. Mac Catalina 下 gdb codesign问题解决
  8. 免费开源工作流Smartflow-Sharp v2.0
  9. 联赛模拟测试10 C. 射手座之日
  10. Java知识系统回顾整理01基础05控制流程06break