所謂回調,就是客戶程序C調用服務程序S中的某個函數SA,然后S又在某個時候反過來調用C中的某個函數CB, 對于C來說,這個CB便叫做回調函數。例如Win32下的窗口過程函數就是一個典型的回調函數。一般說來,C不會自己調用CB,C提供CB的目的就是讓S 來調用它,而且是C不得不提供。由于S并不知道C提供的CB姓甚名誰,所以S會約定B的接口規范(函數原型),然后由C提前通過S的一個函數R告訴S自己 將要使用CB函數,這個過程稱為回調函數的注冊,R稱為注冊函數。Web Service以及Java的RMI都用到回調機制,可以訪問遠程服務器程序。
一個通俗的例子。某天,我打電話向你請教問題,當然是個難題,^_^,你一時想不出解決方法,我又不能拿著電話在那里傻等,于是我們約 定:等你想出辦法后打手機通知我,這樣,我就掛掉電話辦其它事情去了。過了XX分鐘,我的手機響了,你興高采烈的說問題已經搞定,應該如此這般處理。故事 到此結束。這個例子說明了“異步+回調”的編程模式。
熟悉MS-Windows和X Windows事件驅動設計模式的開發人員,通常是把一個方法的指針傳遞給事件源,當某一事件發生時來調用這個方法(也稱為“回調”)。Java的面向對象的模型目前不支持方法指針,似乎不能使用這種方便的機制。
Java支持interface,通過interface可以實現相同的回調。其訣竅就在于定義一個簡單的interface,申明一個被希望回調的方法。
例如,假定當某一事件發生時會得到通知,我們可以定義一個interface:1 public interface InterestingEvent {
2 // 這只是一個普通的方法,可以接收參數、也可以返回值
3 public void interestingEvent();
4 }
這樣我們就有了任何一個實現了這個接口類對象的手柄grip。2 // 這只是一個普通的方法,可以接收參數、也可以返回值
3 public void interestingEvent();
4 }
當一事件發生時,需要通知實現InterestingEvent 接口的對象,并調用interestingEvent() 方法。
1 class EventNotifier {
2 private InterestingEvent ie;
3 private boolean somethingHappened;
4 public EventNotifier(InterestingEvent event) {
5 ie = event;
6 somethingHappened = false;
7 }
8 public void doWork() {
9 if (somethingHappened) {
10 // 事件發生時,通過調用接口的這個方法來通知
11 ie.interestingEvent();
12 }
13 }
14 }
在這個例子中,用somethingHappened 來標志事件是否發生。2 private InterestingEvent ie;
3 private boolean somethingHappened;
4 public EventNotifier(InterestingEvent event) {
5 ie = event;
6 somethingHappened = false;
7 }
8 public void doWork() {
9 if (somethingHappened) {
10 // 事件發生時,通過調用接口的這個方法來通知
11 ie.interestingEvent();
12 }
13 }
14 }
希望接收事件通知的類必須要實現InterestingEvent 接口,而且要把自己的引用傳遞給事件的通知者。
1 public class CallMe implements InterestingEvent {
2 private EventNotifier en;
3 public CallMe() {
4 // 新建一個事件通知者對象,并把自己傳遞給它
5 en = new EventNotifier(this);
6 }
7 // 實現事件發生時,實際處理事件的方法
8 public void interestingEvent() {
9 // 這個事件發生了,進行處理
10 }
11 }
以上是通過一個非常簡單的例子來說明Java中的回調的實現。
2 private EventNotifier en;
3 public CallMe() {
4 // 新建一個事件通知者對象,并把自己傳遞給它
5 en = new EventNotifier(this);
6 }
7 // 實現事件發生時,實際處理事件的方法
8 public void interestingEvent() {
9 // 這個事件發生了,進行處理
10 }
11 }
當然,也可以在事件管理或事件通知者類中,通過注冊的方式來注冊多個對此事件感興趣的對象。
1. 定義一個接口InterestingEvent ,回調方法nterestingEvent(String event) 簡單接收一個String 參數。
1 interface InterestingEvent {
2 public void interestingEvent(String event);
3 }
2. 實現InterestingEvent接口,事件處理類2 public void interestingEvent(String event);
3 }
1 class CallMe implements InterestingEvent {
2 private String name;
3 public CallMe(String name){
4 this.name = name;
5 }
6 public void interestingEvent(String event) {
7 System.out.println(name + ":[" +event + "] happened");
8 }
9 }
3. 事件管理者,或事件通知者2 private String name;
3 public CallMe(String name){
4 this.name = name;
5 }
6 public void interestingEvent(String event) {
7 System.out.println(name + ":[" +event + "] happened");
8 }
9 }
1 class EventNotifier {
2 private List<CallMe> callMes = new ArrayList<CallMe>();
3
4 public void regist(CallMe callMe){
5 callMes.add(callMe);
6 }
7
8 public void doWork(){
9 for(CallMe callMe: callMes) {
10 callMe.interestingEvent("sample event");
11 }
12 }
13 }
4. 測試2 private List<CallMe> callMes = new ArrayList<CallMe>();
3
4 public void regist(CallMe callMe){
5 callMes.add(callMe);
6 }
7
8 public void doWork(){
9 for(CallMe callMe: callMes) {
10 callMe.interestingEvent("sample event");
11 }
12 }
13 }
1 public class CallMeTest {
2 public static void main(String[] args) {
3 EventNotifier ren = new EventNotifier();
4 CallMe a = new CallMe("CallMe A");
5 CallMe b = new CallMe("CallMe B");
6 // regiest
7 ren.regist(a);
8 ren.regist(b);
9
10 // test
11 ren.doWork();
12 }
13 }
2 public static void main(String[] args) {
3 EventNotifier ren = new EventNotifier();
4 CallMe a = new CallMe("CallMe A");
5 CallMe b = new CallMe("CallMe B");
6 // regiest
7 ren.regist(a);
8 ren.regist(b);
9
10 // test
11 ren.doWork();
12 }
13 }