Java——回撥機制

gary-liu發表於2017-06-03

呼叫方式

  1. 同步呼叫:類A的方法a()呼叫類B的方法b(),一直等待b()方法執行完畢,a()方法繼續往下走。這種呼叫方式適用於方法b()執行時間不長的情況,因為b()方法執行時間一長或者直接阻塞的話,a()方法的餘下程式碼是無法執行下去的,這樣會造成整個流程的阻塞。

  2. 非同步呼叫:類A的方法方法a()通過新起執行緒的方式呼叫類B的方法b(),程式碼接著直接往下執行。

  3. 回撥:包括同步回撥和非同步回撥。

    • 類A的a()方法呼叫類B的b()方法
    • 類B的b()方法執行完畢主動呼叫類A的callback()方法

經典回撥方式

Class A實現介面CallBack callback——背景1

class A中包含一個class B的引用b ——背景2

class B有一個引數為callback的方法f(CallBack callback) ——背景3

A的物件a呼叫B的方法 f(CallBack callback) ——A類呼叫B類的某個方法 C

然後b就可以在f(CallBack callback)方法中呼叫A的方法 ——B類呼叫A類的某個方法D

一個經典例子讓你徹徹底底理解java回撥機制

示例

以工人向老闆請假為例:

  • 同步回撥:工人打電話向老闆請假,在電話中一直等待老闆回覆,老闆同意後,再答謝老闆。

  • 非同步回撥:工人打電話向老闆請假,老闆在開會等會給答覆,然後工人掛掉電話幹別的事情並等待老闆的通知,老闆回電話同意請假,工人答謝老闆。

結構設計

Callback 介面中有 replyWorker() 答覆工人請假請求介面,也是老闆決定後需要回撥的方法。

Worker 類實現回撥介面,並持有 Boss 的引用,向 Boss 註冊監聽器,等待 Boss 的回覆。

Boss 類回撥 Worker 的方法來答覆 Worker 的請假。

程式碼實現

Callback 介面

interface Callback {
    /**
     * 答覆工人請假請求
     */
    void replyWorker(String message);
}

Worker 類實現回撥介面,並持有 Boss 的引用,向 Boss 註冊監聽器,等待 Boss 的回覆

class Worker implements Callback {

    private Boss boss;

    public Worker(Boss boss){
        this.boss = boss;
    }

    public void leave(){

        System.out.println("請求批准請假兩天");

        //同步回撥 (可以分別註釋掉同步和非同步回撥的程式碼,看執行效果)
        boss.reply(this);  //工人註冊監聽方法
        System.out.println("同步阻塞等待老闆的答覆後,才能做別的事情");

        //非同步回撥
        new Thread(new Runnable() {
            @Override
            public void run() {
                boss.reply(Worker.this);
            }
        }).start();

        System.out.println("非同步非阻塞,做別的事情並等待老闆的回覆");
    }

    @Override
    public void replyWorker(String message){
        System.out.println("老闆回覆: " + message);
    }

}

Boss 類回撥 Worker 的方法來答覆 Worker 的請假

class Boss {

    public void reply(Callback callback){

        try {
            //老闆思考2s 後回覆
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        callback.replyWorker("同意請假");

    }
}

測試程式碼

public class CallbackPattern {

    public static void main(String[] args){

        Boss boss = new Boss();
        Worker worker = new Worker(boss);
        worker.leave();
    }
}

完整程式碼見 https://github.com/lzx2011/java-scaffold

同步回撥執行結果

請求批准請假兩天
老闆回覆: 同意請假
同步阻塞等待老闆的答覆後,才能做別的事情

非同步回撥執行結果

請求批准請假兩天
非同步非阻塞,做別的事情並等待老闆的回覆
老闆回覆: 同意請假

應用

回撥是一種機制,很多語言裡都有不同的實現,觀察者模式也是回撥的一種具體實現。觀察者模式可以見我的 觀察者模式 文章。回撥機制的應用也很廣泛,例如說java.util.Collections.sort(List, Comparator),這個sort()方法就定義了一個流程實現排序,而具體的順序則由傳入的Comparator引數來確定——這就是一個同步回撥。又例如說GUI程式設計中,一個按鈕被點選之後要做點事情,大家可以註冊個ActionListener上去監聽點選事件,在點選時被呼叫,這就是一個非同步回撥。

總結

回撥的核心就是回撥方將自身的引用傳遞給呼叫方,這樣呼叫方就可以在呼叫完畢之後告訴回撥方它想要知道的資訊。本文主要是我的思考和總結。

相關文章