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:什么是内部类? 大部分时候,类被定义成一个独立的程序单元.在某些情况下,也会把一个类放在另一个类的内部定义,这个定义在其他类内部的类就被称为内部类(有些地方也叫做嵌套类),包含内部类的 ...
随机推荐
- Vijos1327回文词【动态规划】
回文词 回文词是一种对称的字符串--也就是说,一个回文词,从左到右读和从右到左读得到的 结果是一样的.任意给定一个字符串,通过插入若干字符,都可以变成一个回文词.你的任务是写 一个程序,求出将给定字符 ...
- 老李推荐:第14章9节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-遍历控件树查找控件
老李推荐:第14章9节<MonkeyRunner源码剖析> HierarchyViewer实现原理-遍历控件树查找控件 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员 ...
- Java集合总结系列2:Collection接口
Collection 接口是 Java 集合类的一个根接口,Java 在 Collection 接口中定义了许多通用的数据操作类方法以及判断类方法. 通过查看 API 文档或源码的方式,我们可以了解到 ...
- android 学习笔记(1)
内容来源:高成珍.钟元生<Android编程经典案例>学习笔记 表格布局——TableLayout 表格布局以行和列的方式来管理界面的布局,但并不能明确声明包含几行几列.可通过TableR ...
- PixiJS - 基于 WebGL 的超快 HTML5 2D 渲染引擎
Pixi.js 是一个开源的HTML5 2D 渲染引擎,使用 WebGL 实现,不支持的浏览器会自动降低到 Canvas 实现.PixiJS 的目标是提供一个快速且轻量级的2D库,并能兼容所有设备.此 ...
- [原创] IAR7.10安装注册教程
代码开发简单化的趋势势不可挡,TI 公司推出的 IAR7.10 以上版本,集成代码库,方便初学者进行学习移植.本教程详细列出IAR7.10安装以及注册步骤,不足之处望多多交流. 好了进入正题. 第一, ...
- 深入tornado中的IOStream
IOStream对tornado的高效起了很大的作用,他封装了socket的非阻塞IO的读写操作.大体上可以这么说,当连接建立后,服务端与客户端的请求响应都是基于IOStream的,也就是说:IOSt ...
- php写流程管理
流程控制即某个人发起一个流程,通过一层一层审核,通过后,完成整个流程,若有一层审核未通过,中断整个流程.即结束! 比如请假流程: 某一员工发起一个请假流程,那么这个流程的节点人员即他的上级,上上级,上 ...
- 解决md5不是windows平台FIPS验证的加密算法的一部分的怪异问题
一. 发生问题 临近下班时间的下午,领导一句话:项目先上到测试服吧,我明早来看看. 我想项目还没做完,先上到测试服务器,简单看下应该是没什么问题,部署也只是一会儿的事嘛,随后把手头的项目编译,发布,拷 ...
- LinkCode 第k个排列
http://www.lintcode.com/zh-cn/problem/permutation-sequence/# 原题 给定 n 和 k,求123..n组成的排列中的第 k 个排列. 注意事项 ...