最近一直在看Java的相关东西,由于咱们在iOS开发是,不管是Objective-C仍是Swift中,常常会用到委托代理回调,以及Block回调或者说是闭包回调。接下来咱们就来看看Java语言中是如何实现委托代理回调以及闭包回调的。固然这两个技术点虽然实现起来并不困难,可是,这回调在封装一些公用组件时仍是特别有用的。因此今天,仍是有必要把Java中的委托代理回调以及闭包回调来单独的拿出来聊一下。html
本篇博客咱们依然依托于实例,先聊聊委托代理回调的实现和使用场景,而后再聊一下使用匿名内部类来进行回调,其实就是咱们常说的“闭包”回调。闭包回调的实现方式其实就是匿名内部类的使用。既然本篇博客咱们使用到了匿名内部类,咱们就再聊一下Java中的内部类的相关东西。java
1、委托代理回调设计模式
在iOS开发中,咱们常用到委托代理回调,想TableView、CollectionView等等,这些高级控件会依赖于委托回调来完成一些配置。固然在Java中委托代理回调也是很是有用的,接下来咱们就来看一下Java中的委托代理回调。固然在Swift或者OC中的委托代理回调是依托于“协议”的,Swift或者OC中的“协议”其实就是Java语言中的“接口”。因此在Java中的委托代理回调,依然要依托于“接口”来实现。数组
一、类图闭包
首先咱们给出该部分实例的类图,而后咱们根据下方的类图来设计实现咱们的具体代码。下方就是本部分所设计Demo的类图,固然,从类图中咱们也能直观的看到,该示例是比较简单的,一共也就是一个接口两个类。CustomDelegate这个接口是代理类要实现的接口,其中包含了代理类要实现的方法。ide
从下方的类图中咱们能够看出,代理类FirstClass实现了CustomDelegate代理接口,并实现了相关的代理方法。而SecondClass依赖于CustomDelegate接口,也就是说只要是实现了CustomDelegate接口的类均可以做为SecondClass的代理。而FirstClass中含有SecondClass类型的属性,而且FirstClass又实现了CustomDelegate接口,在FirstClass中,咱们将secondClass对象的代理类指定为FirstClass,稍后咱们在具体实现时将会介绍到。post
二、代码的具体实现测试
根据上述类图,咱们很容易的就能够给出相应的代码实现。接下来咱们就根据上述类图来给出具体的代码实现。this
(1)、CustomDelegate的代码实现url
下方代码段就是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对象指定了代理对象就是当前类的对象。具体代码以下所示。
1 package com.zeluli.callback.delegate; 2 3 public class FirstClass implements CustomDelegate { 4 private SecondClass secondClass; 5 6 public void beginRunSecondDelegateMethod() { 7 if(this.secondClass == null) { 8 this.secondClass = new SecondClass(this); 9 } 10 } 11 12 //secondClass回调要执行的方法 13 @Override 14 public void setValue(String value) { 15 System.out.println("第二个类回调过来的值:" + value); 16 } 17 18 }
三、测试用例和运行结果
接下来咱们来看一下上述代码的测试用例和运行结果。下方代码段就是咱们的测试用例,代码比较简单,就是实例化了一个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()方法。
2、闭包回调
上面咱们实现了委托代理回调,接下来咱们来对上述示例进行改造。将其改为匿名内部类的实现方式,也就是使用闭包的形式来实现回调。咱们只须要讲FirstClass进行修改便可。将其委托代理回调修改为闭包回调的形式。下方代码段就是咱们修改后的FirstClass类的源代码。
从下方的源代码能够看出,FirstClass并无实现CustomDelegate接口。在为SecondClass的对象指定委托代理对象时,咱们传入的是一个匿名内部类的对象,而这个对象的类型是CustomDelegate。这种用法,也是匿名内部类的使用方式之一。
修改后的代码的测试用例以及运行结果与以前第一部分的委托代理回调的方式一致,在此就不作过多赘述了。
3、内部类
既然,上述咱们使用到了匿名内部类,那么接下来的这部分咱们就来看看内部类的相关内容。内部类,顾名思义,就是定义在接口、类、方法等结构的内部的类。而匿名内部类,就是没有名字的内部类,这一点也是比较好理解的。下方咱们分别从迭代器的示例以及工厂模式的示例中来窥探一下内部类的具体使用场景及使用规则。固然这两个示例所针对的内部类的角度不一样。
一、迭代器中的内部类
在以前的博客中,咱们详细的聊了迭代器模式,详细内容请移步于《设计模式(十):从电影院中认识"迭代器模式"(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循环往这个序列对象里边添加对象。紧接着咱们从这个序列对象中获取其对应的迭代器对象,而后操做迭代器对序列进行遍历。具体操做以下所示。
二、工厂模式中的匿名内部类
聊完迭代器的内部类,接下来咱们来看一下工厂模式中的匿名内部类。在以前的博客中,咱们详细的聊了工厂模式的具体内容,详情请移步于《设计模式(四):从“兵工厂”中探索简单工厂、工厂方法和抽象工厂模式》。本篇博客咱们就来看一下,匿名内部类在工厂模式中的使用。
(1)、类图
首先咱们来看一下本部分所涉及案例的具体类图,下方就是咱们当前要介绍内容的类图。
Service接口:首先咱们来看一下Service接口,该接口是全部具体的实现类要实现的接口。其中定义这具体的方法声明。咱们的实现类都要继承自该接口。
ServiceFactory接口:该接口是全部工厂类要实现的接口,由于本部分咱们的工厂类是以匿名内部类的形式来体现的,全部该接口就是咱们“匿名内部类”的类型。
Implemention一、2类:这两个类就是咱们的具体实现类,咱们的工厂就负责实例化这两个类。
Factories类:该类就负责调用工厂方法来建立相关实例,并执行实例的相关方法。
(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的相关东西。