java中如何實現"回調函數"

最近工作需要研究了一會別人寫的庫,其中充滿着各種"回調函數",因此把自己理解給記錄下來,存檔。 首先我們來看看回調函數 這個概念的具體由來,百度百科的示義如下:

回調函數就是一個通過函數指針調用的函數。如果你把函數的指針(地址)作爲參數傳遞給另一個函數,當這個指針被用來調用其所指向的函數時,我們就說這是回調函數。回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用於對該事件或條件進行響應。

從上面的這段闡述之中,我們不難發現兩點。

  • 函數回調就是將函數指針的地址當作參數傳遞給另一個函數。

  • 函數回調的用途簡單來說就是進行事件的響應或者事件觸發。

既然我們知道回調函數的用途是事件的響應,那麼我們就從這裏入手。 假設我們有這樣一個場景,一家人坐在一起吃飯,但是我們中國的規矩是,長輩沒動筷子,小輩們是不能動的,所以必須等着長輩動筷子這一事件完成之後,小輩們才能開始。 接下來我們就用回調函數來解決。由於java中沒有指針一說,故而也沒了*,但是java提供了 接口幫我們實現 回調函數,俗稱 接口回調。

首先我們分別創建一個,父親,兒子,姐姐對象。

package zt;

/**
 * 接口回調
 */
public final class App {
    public static void main(String[] args) {
        
    }
}
/**
 * 父親類,裏面有個start函數,表示開始動筷子
 */
class Father{
    private void start(){
        System.out.print("父親開始動筷子了");
    }
}
/**
 * 兒子類,裏面有個start函數,表示開始動筷子
 */
class Son{
    private void start(){
        System.out.print("兒子可以開始動筷子了");
    }
}
/**
 * 姐姐類,裏面有個start函數,表示開始動筷子
 */
class Sister{
    private void start(){
        System.out.print("姐姐可以開始動筷子了");
    }
}

創建好之後,我們要實現,當父親開始動筷子之後,姐姐和弟弟才能開始動筷子。也就是我們必須將父親動筷子這個事件傳遞給姐姐和弟弟對象。

所以按照邏輯,這個父親有一個兒子,一個女孩,並且父親開始動筷子了,他們兩個纔可以動。代碼如下:

package zt;

/**
 * 接口回調
 */
public final class App {
    public static void main(String[] args) {
        new Father(new Son(),new Sister()).start();;
    }
}

interface Start{
    void Fstart(Object obj);
}

/**
 * 父親類,裏面有個start函數,表示開始動筷子
 */
class Father{

    private Sister sister;
    private Son son;

    Father(Son son,Sister sister){
        this.son= son;
        this.sister = sister;
    }

    public void start(){
        System.out.println("父親開始動筷子了");
        son.Fstart("父親動了筷子");
        sister.Fstart("父親動了筷子");
    }
}
/**
 * 兒子類,裏面有個start函數,表示開始動筷子
 */
class Son implements Start{
    private void start(){
        System.out.println("兒子可以開始動筷子了");
    }

    @Override
    public void Fstart(Object obj) {
        if(obj.toString().equals("父親動了筷子")){
            start();
        }
    }
}
/**
 * 姐姐類,裏面有個start函數,表示開始動筷子
 */
class Sister implements Start{
    private void start(){
        System.out.println("姐姐可以開始動筷子了");
    }

    @Override
    public void Fstart(Object obj) {
        if(obj.toString().equals("父親動了筷子")){
            start();
        }
    }
}

然後運行,結果如下: 

這樣看起來是不是很靈活,萬一生個二胎,再加一個就行了。當然上面的代碼並不完美,面向對象的思想告訴我們,我們應該在父親和兒子,姐姐之間再定義一個Children。代碼如下,這樣不管生幾胎就更省事了:

package zt;

/**
 * 接口回調
 */
public final class App {
    public static void main(String[] args) {
        new Father(new Children[] { new Son(), new Sister() }).start();
    }
}

interface Start {
    void Fstart(Object obj);
}

/**
 * 父親類,裏面有個start函數,表示開始動筷子
 */
class Father {

    private Children[] childs;

    Father(Children[] childs) {
        this.childs = childs;
    }

    public void start() {
        System.out.println("父親開始動筷子了");
        for (Children ch : this.childs) {
            ch.Fstart("父親動了筷子");
        }
    }
}

class Children implements Start {

    protected void start() {
        System.out.println("孩子們開始動筷子");
    }

    @Override
    public void Fstart(Object obj) {
        if (obj.toString().equals("父親動了筷子")) {
            this.start();
        }
    }

}

/**
 * 兒子類,繼承孩子類
 */
class Son extends Children {

    @Override
    protected void start() {
        System.out.println("兒子可以開始動筷子了");
    }

}

/**
 * 姐姐類,繼承孩子類
 */
class Sister extends Children {
    @Override
    protected void start() {
        System.out.println("姐姐可以開始動筷子了");
    }
}

這就是我最近的一些感受,說實話工作快3年了,我最近第一次感受到了面向對象編程的優美。當然也有不好的地方,面向對象把有些事複雜化了。一句話,實踐是檢驗真理的唯一標準,紙上得來終覺淺,絕知此事要躬行。

想學習分佈式、微服務、JVM、多線程、架構、java、python的童鞋,千萬不要掃碼,否則後果自負~

林老師帶你學編程https://wolzq.com 

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