国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

以小故事的形式講述Java回調機制,非常有助于理解。

2019-11-11 06:05:37
字體:
來源:轉載
供稿:網友

java的回調機制,可能都聽說過,當然這個機制不僅限于Java,其他各門語言,都應該有使用。但是怎么理解,就有點困惑。還有什么是抽象類回調,什么是接口回調,以及二者之間的差別。也不是一句兩句就能說清楚,就算說的人清楚,但是不能保證,聽的人也能聽的清楚。下面看這個小故事,來深入理解一下回調機制,然后上面的那些問題,也就不攻自破了。

故事背景

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

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

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

小張的煩惱

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

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

public class FileIO {    public boolean saveStrToFile(String fileName, String content) {        try {            File file = getExistsFile(fileName);             writeStrToFile(content, file);            return true;        } catch (IOException e) {            e.PRintStackTrace();            return false;        }    }}

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

public class XiaoZhang {    public void saveStr() {        String fileName = "callback.txt";        String str = "這是一個普通的例子。";        FileIO fileIO = new FileIO();        boolean isSave = fileIO.saveStrToFile(fileName, str);        System.out.println(isSave ? "保存成功" : "保存失敗");    }}

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

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

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

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

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

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

回調

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

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

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

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

于是,FileIO為小張開了一個Vip通道:

public class FileIO {      public void saveStrToFile(final String fileName, String content, final XiaoZhang xiaoZhang) {        new Thread(new Runnable() {            @Override            public void run() {                try {                    File file = getExistsFile(fileName);                     writeStrToFile(content, file);                    xiaoZhang.onResult(true);                } catch (IOException e) {                    e.printStackTrace();                    xiaoZhang.onResult(false);                }            }        }).start();    }}

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

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

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

酒后泄密

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

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

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

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

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

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

public class FileIO {    public void saveStrToFile(String fileName, String str, XiaoZhang xiaoZhang) {    ... ...//同上,省略  }    public void saveStrToFile(String fileName, String str, XiaoLiu xiaoLiu) {    ... ...//同上,省略  }    public void saveStrToFile(String fileName, String str, XiaoWang xiaoWang) {    ... ...//同上,省略  }  ... ...//非常多}

村長支招

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

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

村長果然見(lao)多(jian)識(ju)廣(hua),“小伙子,既然我們村的成員老是需要你的幫助,你就別為每個人開啟一個VIP通道,你直接弄一個我們張家村的VIP通道,

這個通道不是接受張大胖, 張二胖這樣的類, 而是接受一個ZhangClient的抽象類。這個抽象類中只有一個方法:onResult

public abstract class ZhangClient {    public abstract void onResult(boolean isSave);}

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

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

public class FileIO {    public void saveStrToFile(String fileName, String str, ZhangClient zClient) {        new Thread(new Runnable() {            @Override            public void run() {                try {                    File file = getExistsFile(fileName);                    writeStrToFile(str, file);                    zClient.onResult(true);                } catch (IOException e) {                    e.printStackTrace();                    zClient.onResult(false);                }            }        }).start();    }}

public class XiaoZhang extends ZhangClient {    public void saveStr() {        String fileName = "callback.txt";        String str = "這是這個抽象類回調的例子。";        FileIO fileIO = new FileIO();        fileIO.saveStrToFile(fileName, str, this);    }      @Override    public void onResult(boolean isSave) {        System.out.println(isSave ? "保存成功" : "保存失敗");    }}

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

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

Java 巡視組

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

因為李家村的李曉華抱怨說, 我們找你保存個數據, 還得繼承一個姓Zhang的類, 實在是太扯了!

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

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

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

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

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

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

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

public interface IFileIOCallback {    void onResult(boolean isSave);}public class FileIO {    public void saveStrToFile(String fileName, String str, IFileIOCallback callback) {        new Thread(new Runnable() {            @Override            public void run() {                try {                    File file = getExistsFile(fileName);                    writeStrToFile(str, file);                    callback.onResult(true);                } catch (IOException e) {                    e.printStackTrace();                    callback.onResult(false);                }            }        }).start();    }}不幸的是, 大家的代碼也都得改一遍, 不過萬幸的是, 只需要把extends FileIOClient 改為implements IFileIOCallBack即可。
public class XiaoZhang implements IFileIOCallback {    public void saveStr() {        String fileName = "callback.txt";        String str = "這是一個回調的例子。";        FileIO fileIO = new FileIO();        fileIO.saveStrToFile(fileName, str, this);    }    @Override    public void onResult(boolean isSave) {        System.out.println(isSave ? "保存成功" : "保存失敗");    }}

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

尾聲

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

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

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

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

(完)

原文地址:https://xiaoqinyu0000.github.io/Java/JavaCallback/


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 武强县| 宿松县| 吉林市| 梁山县| 东明县| 库尔勒市| 五台县| 军事| 武平县| 门源| 平定县| 仙居县| 晋江市| 荣成市| 翼城县| 柳河县| 广水市| 乐平市| 清徐县| 聊城市| 虎林市| 南宫市| 大兴区| 东安县| 安康市| 修武县| 碌曲县| 临汾市| 无极县| 焉耆| 依兰县| 邹平县| 阳高县| 凤冈县| 浪卡子县| 山丹县| 乌拉特后旗| 金平| 抚远县| 多伦县| 林口县|