如何用匿名內(nèi)部類(lèi)實(shí)現(xiàn) Java 同步回調(diào)
在一個(gè)應(yīng)用系統(tǒng)中,不論使用何種編程語(yǔ)言,模塊之間要進(jìn)行調(diào)用,僅存在三種方式:同步調(diào)用、異步調(diào)用、回調(diào)。本文就其中回調(diào)方式進(jìn)行詳細(xì)解讀,并通過(guò)匿名內(nèi)部類(lèi)的手段,在最后實(shí)現(xiàn)一個(gè)同步回調(diào)的過(guò)程。
一、回調(diào)的意義
在學(xué)習(xí)回調(diào)之前,我們需要知道使用回調(diào)的原因,和回調(diào)的應(yīng)用場(chǎng)景。
不如先思考兩個(gè)問(wèn)題:
棧底對(duì)棧頂通常是不可見(jiàn)的,但是棧頂有時(shí)需要直接調(diào)用棧底 上級(jí)派下級(jí)做事,在此期間,下級(jí)可能需要通過(guò)上級(jí)獲取高權(quán)限的協(xié)助而在本例中,回調(diào)方式被用來(lái)處理爬取后的大量返回?cái)?shù)據(jù)。在業(yè)務(wù)層面,這些數(shù)據(jù)被安排在調(diào)用方進(jìn)行處理,但是調(diào)用方卻沒(méi)有處理這些數(shù)據(jù)的足夠權(quán)限。于是,通過(guò)回調(diào),業(yè)務(wù)被很好的分層并且執(zhí)行。
二、如何實(shí)現(xiàn)同步回調(diào)
本文對(duì)同步回調(diào)的業(yè)務(wù)需求如下:
回調(diào)方調(diào)用調(diào)用方進(jìn)行數(shù)據(jù)爬取 調(diào)用方調(diào)用回調(diào)方進(jìn)行數(shù)據(jù)存儲(chǔ) 調(diào)用方調(diào)用回調(diào)方進(jìn)行日志記錄根據(jù)需求可以得到回調(diào)過(guò)程的時(shí)序圖:
相應(yīng)代碼如下:
public interface Handler { void handle(String info);}public class Task { private String info; private void setInfo(String info) { this.info = info; } public void call() { Crawler.getInstance().crawl(new Handler() { @Override public void handle(String info) {setInfo(info); } }); }}public class Crawler { private static Crawler instance = null; public static Crawler getInstance() { if (instance == null) { instance = new Crawler(); } return instance; } private String getInfo() { return 'the info from crawler'; } public void crawl(Handler handler) { handler.handle(getInfo()); }}
三、遇到的問(wèn)題
如果我們使用代碼來(lái)實(shí)現(xiàn)上述回調(diào)過(guò)程,不難會(huì)發(fā)現(xiàn)這樣一個(gè)問(wèn)題:Task調(diào)用Crawler,Crawler調(diào)用Handler,Hanlder調(diào)用Task。很明顯,此處存在一個(gè)環(huán),產(chǎn)生了循環(huán)依賴的問(wèn)題,而接口可以為我們提供良好的解決方案。
四、為什么通過(guò)匿名內(nèi)部類(lèi)的方式
用 Java 實(shí)現(xiàn)同步回調(diào)有許多方式,為什么我們要通過(guò)匿名內(nèi)部類(lèi)的方式來(lái)實(shí)現(xiàn)回調(diào),直接回調(diào)不香嗎?
不妨先看看直接回調(diào)的順序圖:
相應(yīng)代碼如下:
public interface Handler { void handle(String info);}public class Task implements Handler{ private String info; private void setInfo(String info) { this.info = info; } public void call() { Crawler.getInstance().crawl(this); } @Override public void handle(String info) { setInfo(info); }}public class Crawler { private static Crawler instance = null; public static Crawler getInstance() { if (instance == null) { instance = new Crawler(); } return instance; } private String getInfo() { return 'the info from crawler'; } public void crawl(Handler handler) { handler.handle(getInfo()); }}
直接回調(diào)帶來(lái)的最大問(wèn)題便是回調(diào)接口的暴露,也就是說(shuō)回調(diào)接口不一定用于回調(diào),也可以用于直接訪問(wèn)。這在業(yè)務(wù)層面的設(shè)計(jì)上是絕對(duì)不允許的,而匿名內(nèi)部類(lèi)在執(zhí)行回調(diào)等特定業(yè)務(wù)的同時(shí),可以很好的對(duì)外隱藏用于回調(diào)的接口。
五、總結(jié)
常規(guī)類(lèi)通常無(wú)法對(duì)回調(diào)等特定接口作出限定,要么都可以訪問(wèn),要么都拒絕訪問(wèn)。而內(nèi)部類(lèi)通過(guò)犧牲自身的被訪問(wèn)權(quán)限,提升了自身訪問(wèn)外部類(lèi)的能力,這使得其成為實(shí)現(xiàn)回調(diào)的首選方案。在JAVA8中,lambda表達(dá)式本質(zhì)上就是匿名內(nèi)部類(lèi)的語(yǔ)法糖。
注:匿名內(nèi)部類(lèi)本質(zhì)上是成員內(nèi)部類(lèi)、局部?jī)?nèi)部類(lèi)的簡(jiǎn)化寫(xiě)法,這里將其統(tǒng)稱為內(nèi)部類(lèi)。
參考鏈接
[1] <<Java核心技術(shù)>> 卷一
[2] https://www.cnblogs.com/xrq730/p/6424471.html
以上就是如何用匿名內(nèi)部類(lèi)實(shí)現(xiàn) Java 同步回調(diào)的詳細(xì)內(nèi)容,更多關(guān)于Java 同步回調(diào)的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!
相關(guān)文章:
1. XML在語(yǔ)音合成中的應(yīng)用2. jscript與vbscript 操作XML元素屬性的代碼3. 不要在HTML中濫用div4. HTML5實(shí)戰(zhàn)與剖析之觸摸事件(touchstart、touchmove和touchend)5. .NET Framework各版本(.NET2.0 3.0 3.5 4.0)區(qū)別6. ASP基礎(chǔ)入門(mén)第四篇(腳本變量、函數(shù)、過(guò)程和條件語(yǔ)句)7. ASP將數(shù)字轉(zhuǎn)中文數(shù)字(大寫(xiě)金額)的函數(shù)8. XML入門(mén)的常見(jiàn)問(wèn)題(三)9. php使用正則驗(yàn)證密碼字段的復(fù)雜強(qiáng)度原理詳細(xì)講解 原創(chuàng)10. HTTP協(xié)議常用的請(qǐng)求頭和響應(yīng)頭響應(yīng)詳解說(shuō)明(學(xué)習(xí))
