1. 程式人生 > >函式回撥機制、非同步函式回撥機制圖例詳解

函式回撥機制、非同步函式回撥機制圖例詳解

函式回撥機制,一種雙向呼叫思想,簡單來說就是,如下圖所示: 

         

在層次一中的方法一(函式)呼叫層次二中的方法,並傳入函式二的地址,而這個被呼叫的方法又會呼叫層次一中的方法,這個最後被呼叫的方法二就是回撥方法。方法三呼叫方法二就是回撥的過程。一個有意思的例子,大家可以先感受一下:“諸葛亮給趙子龍一個錦囊,吩咐他危急時開啟按錦囊指示辦, 錦囊裡的命令就是回撥函式,危急時刻就是回撥的時機。”

在Java中,這個“層次”可以理解為類,是兩個類互相呼叫對方的方法;也可以理解為應用類(高層)呼叫類庫方法(低層),並傳入一個自定義的方法以完成某些功能。

說到“呼叫”,模組之間總是存在這一定的介面,模組之間通過這些介面呼叫以通訊聯絡,從呼叫方式上看,可以分為三類:同步呼叫、回撥和非同步呼叫

同步呼叫是一種阻塞式呼叫,也是我們在寫程式中經常使用的;

回撥是一種雙向的呼叫模式;

非同步呼叫是一種類似訊息或事件的機制,解決了同步阻塞的問題,舉例來講:A通知B後,他們各走各的路,互不影響,不用像同步呼叫那樣,A通知B後,非得等到B走完後,A才繼續走。回撥是非同步呼叫的基礎。下面以一個網路上很流行的例子為基礎,理解非同步回撥機制。

非同步回撥典型例子:

提問者A有個問題"1+1=?",於是A打電話給回答者B,B說他現在很忙,忙完了才能給他想答案,A心想我不能這麼一直等著把,於是說:“那咱們約定好,B你想出答案了以打電話的形式告訴我”,掛了電話A也去忙他自己的事了,過了一會B想出答案按A約定好的方式打電話告訴了B答案。

下面以程式碼形式描述這個過程:

/** 
 * 這是一個回撥介面,裡面定義的方法就是回撥函式
 */  
public interface CallBack {
	/** 
	 * 這是一個回撥函式,用於回答者B知道答案後給提問者A回電話,並告知提問者A答案是什麼
	 * 這個回電話的方式callBack是提問者A確定的,所以這個方法的實現類是A類
	 * 這個回電話的內容result是回答者B提供的,所以這個變數的值是在B類中確定的
	 */ 
	public void callBack(String result);
}
/** 
 * 提問者A類
 */ 
public class A implements CallBack{

	/** 
	 * 提問者A是知道回答者B的聯絡方式的
	 * 這裡以一個B類引用代表,並在構造方法中傳入B例項物件
	 */ 
	private B b;
	public A(B b){
		this.b = b;
	}
	/** 
	 * 提問者A向回答者B打電話提問題					
	 * 這裡以一個call方法表示,並把問題引數傳入
	 */ 
	public void call(final String question){  
		/** 
		 * 建立提問者A執行緒,與回答者B執行緒結合,構成一個非同步的環境
		 */ 
        new Thread(new Runnable() {  
            @Override  
            public void run() {
                /** 
                 * B接電話,聽問題
                 * 這裡以呼叫回答者B的answer方法表示,傳入回撥方法類引數、問題引數,以表示誰打的電話,問啥了 
                 * 因為A類實現了CallBack介面,所以A類就是回撥方法類,回撥方法類實現了回撥方法
                 */  
                b.answer(A.this, question);   
            }  
        }).start();            
        /** 
		 * 提問者提完問,去幹別事情
		 */   
        doOtherThing();  
    }  
	
	public void doOtherThing(){
		System.out.println("我是提問者A,我問完問題就去幹別的事情了!");
	}
	
	/** 
	 * 剛剛說到,這個回電話的方式callBack是提問者A確定的,所以這個方法的實現類是A類
	 * 所以這裡實現回撥方法,代表回覆的方法是回電話,由回答者B呼叫	 
	 */ 
	@Override
	public void callBack(String result) {
		System.out.println("B呼叫A定義的回撥函式:回答者B告訴提問者A,問題的答案是:"+ result);
	}
	
}
/**
 * 回答者B類
 */
public class B {
	/**
	 * 回答者B接電話,聽問題 這裡以呼叫回答者B的answer方法表示,傳入回撥方法類、問題引數,以表示誰打的電話,問啥了 
	 */
	public void answer(CallBack callBack, String question) {
		System.out.println("A呼叫B的接電話方法:我是回答者B,提問者A問的問題是:" + question);
		/**
		 * 模擬回答者B先忙自己的事 
		 */
		System.out.println("我是回答者B,我接完電話先去忙我自己的事!");
		for (int i = 0; i < 100000; i++) {

		}
		String result = "2";
		System.out.println("我是回答者B,我知道了答案是:" + result);
		/**
		 * 呼叫回撥函式,打電話告知A答案是什麼						
		 */
		callBack.callBack(result);
	}
}
/** 
 * 場景測試類
 */  
public class test {
	public static void main(String args[]){
		 /** 
		 * 例項化回答者B
		 */  
		B b = new B();
		 /** 
		 * 例項化提問者A
		 */  
		A a = new A(b);
		 /** 
		 * A向B提問,開始
		 */  
		a.call("1 + 1 = ?");		
	}
}

(例子原版源自:xiaanming的部落格(http://blog.csdn.net/xiaanming/article/details/17483273))

執行結果:


函式回撥機制也應用於鉤子方法,這個可以參考部落格:點選開啟連結