最近一直在看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的相關東西。