最近一直在看 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()); //执行委托代理回调方法
- }
- };
- longdelay = 0;
- Timer timer =new Timer();
- timer.scheduleAtFixedRate(task, delay, 1000);
- }
- private String getNowDate() {
- Date currentTime =new Date();
- SimpleDateFormat formatter =newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- String dateString = formatter.format(currentTime);
- return dateString;
- }
- }
(3)、FirstClass 的创建
接下来我们来创建委托代理类,也就是我们的 FirstClass 类。其中的代码也是比较简单的,FirstClass 类实现了 CustomDelegate 的相关方法,然后为 secondClass 对象指定了代理对象就是当前类的对象。具体代码如下所示。
- 1 package com.zeluli.callback.delegate;
- 2
- 3 public classFirstClassimplements CustomDelegate {
- 4 private SecondClass secondClass;
- 5
- 6 public void beginRunSecondDelegateMethod() {
- 7 if(this.secondClass ==null) {
- 8 this.secondClass =newSecondClass(this);
- 9 }
- 10 }
- 11
- 12 //secondClass回调要执行的方法
- 13 @Override
- 14 public void setValue(String value) {
- 15System.out.println("第二个类回调过来的值:" + value);
- 16 }
- 17
- 18}
3、测试用例和运行结果
接下来我们来看一下上述代码的测试用例和运行结果。下方代码段就是我们的测试用例,代码比较简单,就是实例化了一个 FirstClass 的类对象 firstObj,然后调用相应的方法为其中的 secondClass 指定代理方法即可,具体如下所示。
- package com.zeluli.callback.delegate;
- public class Main {
- public static voidmain(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 就是我们创建的迭代器接口。
为了统一迭代器使用规范性,所有的迭代器都要遵循该接口。具体代码如下所示。
(2)、创建序列类以及迭代器内部类
下方创建的就是我们的序列类 Sequence,该类中的 items 数组用来存储元素,而 next 属性指向当前值的下标。在 Sequence 类中,除了属性、构造器以及方法外,我们还在其中定义了一个内部类 SequenceSelector。
SequenceSelector 类就是 Sequence 类的迭代器,并且 SequenceSelector 要实现迭代器接口 Selector。下方我们要注意的一点,在内部类 SequenceSelector 中,可以直接访问外层类 Sequence 类的成员属性和方法。因为无论是内部类还是 Sequence 类的成员属性,都在 Sequence 类的域中。
当然下方的代码的逻辑是比较简单的,主要是对 items 数组的操作。具体代码如下所示。
(3)、上述迭代器的使用
定义完迭代器后,接下来,我们就来看一下迭代器的使用呢。首先我们创建一个序列对象,然后通过 for 循环往这个序列对象里边添加对象。紧接着我们从这个序列对象中获取其对应的迭代器对象,然后操作迭代器对序列进行遍历。具体操作如下所示。
2、工厂模式中的匿名内部类
聊完迭代器的内部类,接下来我们来看一下工厂模式中的匿名内部类。在之前的博客中,我们详细的聊了工厂模式的具体内容,详情请移步于《设计模式 (四):从 "兵工厂" 中探索简单工厂、工厂方法和抽象工厂模式》。本篇博客我们就来看一下,匿名内部类在工厂模式中的使用。
(1)、类图
首先我们来看一下本部分所涉及案例的具体类图,下方就是我们当前要介绍内容的类图。
(2)、Service 和 ServiceFactory 接口的具体实现
这两个接口的实现代码比较简单,在此就不做过多赘述了,具体代码如下所示:
- 1 package com.zeluli.innerclass.factory;
- 2
- 3 public interface Service {
- 4 void method1();
- 5 void method2();
- 6 }
- 7
- 8====================================================== 9
- 10 package com.zeluli.innerclass.factory;
- 11
- 12 public interface ServiceFactory {
- 13 Service getService();
- 14}
(3)、Implementation 相关类的实现
Implementation1 和 Implementation2 的实现差不多,我们就聊一下 Implementation1 类的具体代码。从下方代码片段中我们可以看出 Implementation1 类实现了 Service 接口,并且给出了接口中相关方法的实现。并且在 Implementation1 类中有一个 ServiceFactory 类型的静态变量 factory。而 factory 引用的是一个 ServiceFactory 类型的匿名内部类的对象。该匿名内部类就是一个工程类,其中有一个方法负责创建当前外围类,也就是 Implementation1 类的对象。具体实现如下所示。
(4)、Factory 类的实现
接下来我们就来看看 Factory 类的实现,Factory 中就负责从工厂中获取相应的对象,然后执行对象的相关方法,代码比较简单,就不做过多赘述了。
(5)、测试用例与运行结果
接下来我们来看一下上述实例的测试用例以及输出结果,如下所示:
今天的博客就先到这儿,下篇博客会继续聊 Java 的相关东西。
来源: http://www.cnblogs.com/ludashi/p/6732613.html