Java帝國之撥雲見日識回調

2017-01-24 王欽譽 Java編程

來自:碼農翻身(微信號:coderising)

作者:王欽譽

前言:本文原作者是王欽譽,原文鏈接:https://xiaoqinyu0000.github.io/Java/JavaCallback/ (點擊尾部閱讀原文前往)


文章主要介紹Java的回調機制及其實現。


故事背景


在日常編程中,我們經常需要對內存的數據進行持久化的工作,把他們保存在硬盤文件或者數據庫中。


爲了避免重複, 我們通常會把這部分工作封裝在一個工具類中, 讓各個客戶端來調用。


下文的FileIO就是一個簡單的工具類(爲了簡單起見,並沒有使用單例或靜態方法來實現)


小張的煩惱


Java 帝國的FileIO是一個忙碌的傢伙,附近7、8個村落的人都來找他, 請他把數據存儲到硬盤裏。


FileIO提供了一個簡單的接口, 大家只要告訴他文件名和要保存的字符串內容, 剩下的事就只是等待了,FileIO會完成工作,告訴大家是成功還是失敗。



比如張家村的小張來請FileIO保存文件的時候是這樣的:


通常情況下, 小張都會很快拿到返回結果, 高高興興的回家。


但這一次不知道怎麼回事, 這個FileIO一直不返回結果, 把小張阻塞了長達1秒鐘!


小張說: “哥們, 怎麼回事? 我這兒都等了1000毫秒了, 還沒完?


FileIO回答 : ”這不能怪我啊, 你這次的數據量實在是太大了,是誰上傳的大文件故意搗亂吧, 對了, 你殺毒沒有?“


"安全問題不用你考慮 " 小張也有點底氣不足 :”我覺得數據量還行, 也有可能是硬盤這會兒太忙了”


總之,小張一直阻塞在那裏,無法回家。  


回調


阻塞的事情發生的多了,極大的影響了小張的工作, 最近這一週的工分可是落後了不少啊, 再這麼下去,月底分糧的時候就要餓肚子了, 餓肚子還是小事, 自己喜歡的張二妮看到沒糧食,估計就不理我了。。。


他拎了兩瓶好酒去找FileIO商量: “兄弟, 我聽說有一種異步保存的辦法,  你那邊能不能用下?  保存數據的時候起一個線程, 把主線程讓回給我,保存好了再通知我,我也不用老是等你,是吧?”


FIleIO想了想說:“這樣確實可以解決問題,但每天找我保存數據的人也很多,而且我也不知道在完成數據的寫入之後怎麼通知你呢?”


小張把兩瓶好酒往前一推, “我們關係這麼好,你再開個專屬我的方法唄,我在調用你的saveStrToFile方法的時候順便把我的實例給你,你搞完之後通過我的實例調用我的方法通知我就行啦。就調我的onResult()這個方法吧。這事要保密, 天知地知你知我知就行了”。


於是,FileIO爲小張開了一個VIP通道:

這種方式很巧妙,小張調用FileIO的saveStrToFile(String,String,XiaoZhang)的時候,把自己的實例通過第三個參數給了FileIO,FileIO開啓子線程保存完數據之後,通過XiaoZhang給的實例回調onResult(boolean)方法。


聽起來很繞口,但總結起來就我調你的方法,你再回調我的方法


後來,JAVA帝國給這種機制取了個名字叫回調機制,在帝國中廣爲人知。


酒後泄密


由於有了FileIO的VIP通道,小張處理業務的能力大幅度提升, 工分不但在張家村獨佔鰲頭, 就是算上李家村, 劉家村 等,那也是數一數二的。


小張一時風光不已,越來越多的人來向他請教祕訣,但小張卻笑而不語(這可是成功祕訣,能告訴你們嘛...)。


有一次, 李家村的小李看到了FileIO有了一個新接口(畢竟都是公開的嘛), 但是不知道怎麼回事, 自己也調用不了, 類型不對啊。


小李別有用心的請小張和FileIO喝酒, 酒過三巡, 倆人終於吐露了這個祕密。


這一下子炸開了鍋, 雖然Java 帝國規定, 接口的設計一定要規範, 不能亂來, 但是大家蜂擁而至, 紛紛要求FileIO 給自己也開VIP通道。


FileIO實在是沒有辦法, 無奈之下爲小李, 小王等等都開啓了VIP通道:



村長支招

隨着FileIO開啓的VIP通道越來越多,FIleIO發現自己的體積越來越膨脹,自己有大量的代碼是在處理這些VIP通道,而且處理方式都差不多,VIP通道多了也就失去其意義了。


有一次, 張家村德高望重的村長路過FileIO這裏,FileIO知道村長軟件設計能力了得, 趕緊拉住就行討教。


村長果然見(lao)多(jian)識(ju)廣(hua),“小夥子,既然我們村的成員老是需要你的幫助,你就別爲每個人開啓一個VIP通道,你直接弄一個我們張家村的VIP通道,這個通道不是接受張大胖, 張二胖這樣的類, 而是接受一個ZhangClient的抽象類。這個抽象類中只有一個方法:onResult

每次,有人去找你幫忙的時候,你也不用管具體是誰,只要他實現了ZhangClient,你就知道它有一個onResult(false)的方法,你處理完了之後直接回調它的onResult(boolean)方法就行了,是不是很簡單啊,哈哈哈哈哈~~~”


FileIO聽完老村長的話恍然大悟,這一層解決不了的事,那我們再加一層,在上一層解決唄


如上所示,FileIO表面上回調了ZhangClient 的onResult(false)方法,但實際上回調的是XiaoZhang的onResult(false)方法,因爲傳進來的實例實際上是繼承了ZhangClient的小張(作者:感覺像披着羊皮的狼)。


後來,帝國將這種利用抽象類去實現回調的方式稱之爲抽象類回調


Java 巡視組


FileIO把其他通道都刪除了, 只留了一個ZhangClient通道, 現在他明白老村長的老奸巨猾了。  


因爲李家村、趙家村、王家村的人都抱怨說, 我們找你保存個數據, 還得繼承一個姓Zhang的類, 實在是太扯了!


FileIO想了想, 得了, 爲了避免引起衆怒, 還是改個名稱吧, 就叫FileIOClient 。


即使是這樣, 很多人還在抱怨: 我已經繼承了一個類了, 怎麼可能再繼承你這個FileIOClient ?  不繼承就沒法保存數據, 還有沒有王法了!   還有,你這老是改來該去, 把我們都該累死了。


事情鬧大了, 上面派了個巡視組下來解決。


FileIO戰戰兢兢的給巡視組訴苦: ”我也實在是沒辦法啊, 你看Java也不允許多繼承, 我昨晚想起一個辦法, JAVA類都隱性繼承Object,能不能在Object裏面增加一個回調的方法?“


巡視組生氣的說:”別做夢了! java.lang.Object是我們的根, 那是你加方法的地方嗎?!  你整天只知道保存數據, 難道都忘了Java帝國的接口(interface)了嗎?“


FileIO被點醒了, 既然繼承的方式搞不定,那就接口好了, 接口可以隨意實現, 想實現幾個實現幾個。


在巡查組的監視下, FileIO很快修改了代碼:


不幸的是, 大家的代碼也都得改一遍,  萬幸的是, 只需要把extends FileIOClient 改爲implements IFileIOCallBack即可。

後來,帝國將這種利用接口去實現回調機制的方式稱之爲接口回調。


尾聲


張家村的小張有點落寞, 他原來獨有的回調方法現在已經被接口回調所替代,他獨有的優勢已經蕩然無存,風光不再。


更讓他煩心的事, 隨着FileIO接口的變化, 他的代碼也不斷的改來改去, 光是修改就耽誤了不少事兒,少掙了好多工分。


不就是一個回調嗎, 還繼承這個, 實現那個的, 這Java 搞的也太複雜了。


有小道消息說,Java帝國之外的動態語言王國有個叫Duck Typing 的東西, 實現回調的時候根本不用繼承什麼東西, 也不用實現什麼接口, 只要自己有一個onResult方法, 就可以被調用, 小張好奇心大起,決定去出去闖一闖。


(完)


來自:碼農翻身(微信號:coderising)


附:頭圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章