Java编程之委托代理回调、内部类以及匿名内部类回调(闭包回调)
最近一直在看Java的相关东西,因为我们在iOS开发是,无论是Objective-C还是Swift中,经常会用到委托代理回调,以及Block回调或者说是闭包回调。接下来我们就来看看Java语言中是如何实现委托代理回调以及闭包回调的。当然这两个技术点虽然实现起来并不困难,但是,这回调在封装一些公用组件时还是特别有用的。所以今天,还是有必要把Java中的委托代理回调以及闭包回调来单独的拿出来聊一下。
本篇博客我们依然依托于实例,先聊聊委托代理回调的实现和使用场景,然后再聊一下使用匿名内部类来进行回调,其实就是我们常说的“闭包”回调。闭包回调的实现方式其实就是匿名内部类的使用。既然本篇博客我们使用到了匿名内部类,我们就再聊一下Java中的内部类的相关东西。
一、委托代理回调
在iOS开发中,我们经常使用到委托代理回调,想TableView、CollectionView等等,这些高级控件会依赖于委托回调来完成一些配置。当然在Java中委托代理回调也是非常有用的,接下来我们就来看一下Java中的委托代理回调。当然在Swift或者OC中的委托代理回调是依托于“协议”的,Swift或者OC中的“协议”其实就是Java语言中的“接口”。所以在Java中的委托代理回调,依然要依托于“接口”来实现。
1、类图
首先我们给出该部分实例的类图,然后我们根据下方的类图来设计实现我们的具体代码。下方就是本部分所设计Demo的类图,当然,从类图中我们也能直观的看到,该示例是比较简单的,一共也就是一个接口两个类。CustomDelegate这个接口是代理类要实现的接口,其中包含了代理类要实现的方法。
从下方的类图中我们可以看出,代理类FirstClass实现了CustomDelegate代理接口,并实现了相关的代理方法。而SecondClass依赖于CustomDelegate接口,也就是说只要是实现了CustomDelegate接口的类都可以作为SecondClass的代理。而FirstClass中含有SecondClass类型的属性,并且FirstClass又实现了CustomDelegate接口,在FirstClass中,我们将secondClass对象的代理类指定为FirstClass,稍后我们在具体实现时将会介绍到。

2、代码的具体实现
根据上述类图,我们很容易的就可以给出相应的代码实现。接下来我们就根据上述类图来给出具体的代码实现。
(1)、CustomDelegate的代码实现
下方代码段就是CustomDelegate的具体实现。当然该接口的实现比较简单,就一个setValue(String value)方法。该方法的具体作用是用来相应参数回调的。下方我们会用到该方法。
package com.zeluli.callback.delegate;
public interface CustomDelegate {
public void setValue(String value);
}
(2)、SecondClass的代码实现
CustomDelegate实现完毕后,接下来我们就来实现一下SecondClass的具体代码。下方代码段就是SecondClass的具体代码实现了。我们从具体实现中可以明确看出,SecondClass类中有个私有的delegate属性,该属性是CustomDelegate类型的,所以SecondClass依赖于CustomDelegate类型。
在SecondClass的构造方法中,我们为delegate指定了具体的对象,然后调用了begin()方法。begin()方法中做的事情也是比较简单的,就是使用了Java中自带的定时器,然后在特定时间的间隔中执行delegate对象的setValue()方法,并且将当前的时间传给setValue()方法。
package com.zeluli.callback.delegate; import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class SecondClass {
private CustomDelegate delegate; public SecondClass(CustomDelegate delegate) {
this.delegate = delegate;
this.begin();
} public void begin() {
TimerTask task = new TimerTask() {
@Override
public void run() {
delegate.setValue(getNowDate()); //执行委托代理回调方法
}
}; long delay = 0;
Timer timer = new Timer();
timer.scheduleAtFixedRate(task, delay, 1000);
} private String getNowDate() {
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = formatter.format(currentTime);
return dateString;
}
}
(3)、FirstClass的创建
接下来我们来创建委托代理类,也就是我们的FirstClass类。其中的代码也是比较简单的,FirstClass类实现了CustomDelegate的相关方法,然后为secondClass对象指定了代理对象就是当前类的对象。具体代码如下所示。
package com.zeluli.callback.delegate;
public class FirstClass implements CustomDelegate {
private SecondClass secondClass;
public void beginRunSecondDelegateMethod() {
if(this.secondClass == null) {
this.secondClass = new SecondClass(this);
}
}
//secondClass回调要执行的方法
@Override
public void setValue(String value) {
System.out.println("第二个类回调过来的值:" + value);
}
}
3、测试用例和运行结果
接下来我们来看一下上述代码的测试用例和运行结果。下方代码段就是我们的测试用例,代码比较简单,就是实例化了一个FirstClass的类对象firstObj,然后调用相应的方法为其中的secondClass指定代理方法即可,具体如下所示。
package com.zeluli.callback.delegate;
public class Main {
public static void main(String[] args) throws InterruptedException {
FirstClass firstObj = new FirstClass();
firstObj.beginRunSecondDelegateMethod();
}
}
下方就是上述代码的运行结果,我们可以看出定期会执行FirstClass中的setValue()方法。

二、闭包回调
上面我们实现了委托代理回调,接下来我们来对上述示例进行改造。将其改成匿名内部类的实现方式,也就是使用闭包的形式来实现回调。我们只需要讲FirstClass进行修改即可。将其委托代理回调修改成闭包回调的形式。下方代码段就是我们修改后的FirstClass类的源代码。
从下方的源代码可以看出,FirstClass并没有实现CustomDelegate接口。在为SecondClass的对象指定委托代理对象时,我们传入的是一个匿名内部类的对象,而这个对象的类型是CustomDelegate。这种用法,也是匿名内部类的使用方式之一。

修改后的代码的测试用例以及运行结果与之前第一部分的委托代理回调的方式一致,在此就不做过多赘述了。
三、内部类
既然,上述我们使用到了匿名内部类,那么接下来的这部分我们就来看看内部类的相关内容。内部类,顾名思义,就是定义在接口、类、方法等结构的内部的类。而匿名内部类,就是没有名字的内部类,这一点也是比较好理解的。下方我们分别从迭代器的示例以及工厂模式的示例中来窥探一下内部类的具体使用场景及使用规则。当然这两个示例所针对的内部类的角度不同。
1、迭代器中的内部类
在之前的博客中,我们详细的聊了迭代器模式,详细内容请移步于《设计模式(十):从电影院中认识"迭代器模式"(Iterator Pattern)》。当然之前的迭代器我们是使用的Swift3.0来实现的,今天博客中我们就用Java的内部类来实现一个Java中的迭代器。
(1)、迭代器接口
按照之前的介绍迭代器的套路,我们还是先要创建迭代器接口的。下方的Selector就是我们创建的迭代器接口。
end()方法用来判断序列是否到达了结尾处。
current()方法则用来获取当前序列中下标的值。
next()方法则是移动下标到下一个位置。
为了统一迭代器使用规范性,所有的迭代器都要遵循该接口。具体代码如下所示。

(2)、创建序列类以及迭代器内部类
下方创建的就是我们的序列类Sequence,该类中的items数组用来存储元素,而next属性指向当前值的下标。在Sequence类中,除了属性、构造器以及方法外,我们还在其中定义了一个内部类SequenceSelector。
SequenceSelector类就是Sequence类的迭代器,并且SequenceSelector要实现迭代器接口Selector。下方我们要注意的一点,在内部类SequenceSelector中,可以直接访问外层类Sequence类的成员属性和方法。因为无论是内部类还是Sequence类的成员属性,都在Sequence类的域中。
当然下方的代码的逻辑是比较简单的,主要是对items数组的操作。具体代码如下所示。

(3)、上述迭代器的使用
定义完迭代器后,接下来,我们就来看一下迭代器的使用呢。首先我们创建一个序列对象,然后通过for循环往这个序列对象里边添加对象。紧接着我们从这个序列对象中获取其对应的迭代器对象,然后操作迭代器对序列进行遍历。具体操作如下所示。

2、工厂模式中的匿名内部类
聊完迭代器的内部类,接下来我们来看一下工厂模式中的匿名内部类。在之前的博客中,我们详细的聊了工厂模式的具体内容,详情请移步于《设计模式(四):从“兵工厂”中探索简单工厂、工厂方法和抽象工厂模式》。本篇博客我们就来看一下,匿名内部类在工厂模式中的使用。
(1)、类图
首先我们来看一下本部分所涉及案例的具体类图,下方就是我们当前要介绍内容的类图。
Service接口:首先我们来看一下Service接口,该接口是所有具体的实现类要实现的接口。其中定义这具体的方法声明。我们的实现类都要继承自该接口。
ServiceFactory接口:该接口是所有工厂类要实现的接口,因为本部分我们的工厂类是以匿名内部类的形式来体现的,所有该接口就是我们“匿名内部类”的类型。
Implemention1、2类:这两个类就是我们的具体实现类,我们的工厂就负责实例化这两个类。
Factories类:该类就负责调用工厂方法来创建相关实例,并执行实例的相关方法。

(2)、Service和ServiceFactory接口的具体实现
这两个接口的实现代码比较简单,在此就不做过多赘述了,具体代码如下所示:
package com.zeluli.innerclass.factory;
public interface Service {
void method1();
void method2();
}
======================================================
package com.zeluli.innerclass.factory;
public interface ServiceFactory {
Service getService();
}
(3)、Implementation相关类的实现
Implementation1和Implementation2的实现差不多,我们就聊一下Implementation1类的具体代码。从下方代码片段中我们可以看出Implementation1类实现了Service接口,并且给出了接口中相关方法的实现。并且在Implementation1类中有一个ServiceFactory类型的静态变量factory。而factory引用的是一个ServiceFactory类型的匿名内部类的对象。该匿名内部类就是一个工程类,其中有一个方法负责创建当前外围类,也就是Implementation1类的对象。具体实现如下所示。

(4)、Factory类的实现
接下来我们就来看看Factory类的实现,Factory中就负责从工厂中获取相应的对象,然后执行对象的相关方法,代码比较简单,就不做过多赘述了。

(5)、测试用例与运行结果
接下来我们来看一下上述实例的测试用例以及输出结果,如下所示:

今天的博客就先到这儿,下篇博客会继续聊Java的相关东西。
Java编程之委托代理回调、内部类以及匿名内部类回调(闭包回调)的更多相关文章
- Java编程的逻辑 (21) - 内部类的本质
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- Java编程思想学习(八) 内部类
可以将一个类的定义放在另一个类的定义内部,这就是内部类. 内部类的定义是简单的,但是它的语法确实很是复杂,让人不是很好理解.下面就内部类做一个小结. 一.内部类的分类 总的来讲内部类分为普通内部类,匿 ...
- Java编程思想之十 内部类
可以将一个类定义放在另一个类的定义内部,这就是内部类. 10.1 创建内部类 创建内部类就是把类的定义置于外部类里面. public class Parcell { class contents{ i ...
- Java -- 内部类, 成员内部类,局部内部类,匿名内部类,闭包和回调, 枚举类
1. 成员内部类分为 静态内部类 和 非静态内部类. 非静态内部类 和 外部类的其他成员一样处理, 非静态内部类可以访问外部类的private的属性,而外部类不能访问非静态内部类的属性,需要实例非静 ...
- Java编程思想:利用内部类实现的工厂模式
public class Test { public static void main(String[] args) { Factories.test(); } } /* 设计模式之禅中的工厂模式是这 ...
- Java面向对象程序设计--接口和内部类
1.接口的定义: In the Java programming language, an interface is not a class but staff[0] = ...
- Java中的内部类(成员内部类、静态内部类、局部内部类、匿名内部类)
Java中的内部类(成员内部类.静态内部类.局部内部类.匿名内部类) 神话丿小王子的博客主页 我们先看这样一段话:人是由大脑.肢体.器官等身体结果组成.而组成我们人体的心脏它也有自己的属性和行为(血液 ...
- “全栈2019”Java第一百一十章:局部内部类与匿名内部类区别详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- java 内部类、匿名内部类
一:内部类 1:什么是内部类? 大部分时候,类被定义成一个独立的程序单元.在某些情况下,也会把一个类放在另一个类的内部定义,这个定义在其他类内部的类就被称为内部类(有些地方也叫做嵌套类),包含内部类的 ...
随机推荐
- Flash加载ini文件!
这个帖子里有解决方案: http://bbs.9ria.com/thread-405128-1-1.html
- Debian 8开启sftp服务
看到某云的CDN居然是使用ftp这种早该淘汰的协议,不禁有些吐槽.ftp曾经作为互联网上最重要的协议,但漫长使用过程中体现出的各种缺点,已不适合再使用.其中最致命的问题就是明文传输用户密码.建议使用这 ...
- sublime Text3插件无法安装解决方法(提示There are no packages available installation)
第一步 在sublime Text3界面按"ctrl+."出现一个输入框界面 第二步 在输入框输入: import urllib.request,os,hashlib; h = ' ...
- 某直播App问题分析
某直播App问题分析 一. 出现问题 观看自己开播的直播间,经常出现卡顿,而且画面一卡6,7s,重新播放时会出现跳帧,卡顿频率也较高,导致该App可用性极低. 二. 分析 1. 直播架构分析 根据lo ...
- JavaEE开发使用Maven管理的SpringMVC工程
前几篇博客已经陆陆续续的聊了一些Spring的东西,今天博客我们就来聊一下SpringMVC.SpringMVC目前在JavaEE开发中可谓占据一席之地,用起来也是比较顺手的.低耦合,高内聚,利用一些 ...
- Web worker 与JS中异步编程的对比
0.从一道题说起 var t = true; setTimeout(function(){ t = false; }, 1000); while(t){ } alert('end'); 问,以上代码何 ...
- 做一个完整的纯react-naitve安卓应用【从环境安装到应用发布】
前提:从来没有写过android 跟 ios 应用,是一个小前端.前一段时间玩了一下 react-native 感觉还不错,应用代码还未开源. 环境: win7 成果: ...
- Java 判断回文字符串有多少和其中的最大字符串
一.简介代码功能 该代码的功能可以实现对任意的一段字符串进行判断是否有回文,回文有哪些,和其中的最大回文. 二.代码部分 1.全局变量 static String hws = "" ...
- Java --- JSP2新特性
自从03年发布了jsp2.0之后,新增了一些额外的特性,这些特性使得动态网页设计变得更加容易.jsp2.0以后的版本统称jsp2.主要的新增特性有如下几个: 直接配置jsp属性 表达式语言(EL) 标 ...
- Web前端相关资源
Web前端相关 GRUNT: js task runner Sea.js: js模块化 knockout.js:MVVM开发前台,绑定技术 Angular.js: 使用超动感HTML & JS ...