25 12月 2009

Callback just like?

這篇想寫有段時間了,因為前兩週有個工作多年的同行在問,callback是什麼....但一直沒寫的原因是不想畫圖,不想寫sample code...

Callback是什麼?看起來很容易啊,就"叫回去"咩...似乎"回去叫"比較符合文法,這是簡單基本的東西,連Design Pattern都不屑列進去,但是只寫Java的人可能比較不能想像,因為Java沒有function pointer,所以比較不容易舉例,反而是寫過C(++),JavaScript的人比較容易理解.

簡單說, Callback就是將function當做參數傳給被呼叫的程式, 只碰Java的應該就頭大了,將function(method)當參數?!

先談談程式運作的模式吧,用別人的Library寫系統有幾種方式,

一是事必躬親,站在旁邊看著別人做完一步,再決定下一步要做什麼

二是先告訴對方我是誰,能做什麼事,等他有空時要處理我的工作時候再叫我過去

三是留紙條給他,叫他照著辦,心情好再留個電話給他,叫他辦完時要回報一下

第一種情形像什麼,用過JDBC library的應該很清楚,

Connection conn = ds.getConnection(...);
PreparedStatement preStat = conn.prepareStatement(...);
preStat.setObject(....)
....
preStat.execute();
conn.close();
很熟悉吧?

第二種情形呢,比較像是用Observer Pattern來做事

interface Observable {
 public void notifyObservers();
 public void register(Observer obs);
 public void unRegister(Observer obs);
}
interface Observer {
 public void available(Observable ob);
}

Observable利用Observer.available()來告訴Observer說我現在有空了,一起來玩吧...當然也可以讓Observable呼叫Observer的其他method來做事,只是這代表這兩個人要夠熟,不過由於是別人寫的API,所以Observable要完全認識你所寫Observer的機會不太高,只好將這定成Interface,能做的事情都定在Interface上囉

第三種就直接明瞭

class ThatCallsBack:public class Caller{
public:
 ThatCalls(T *who,void (T::*func)(void)):
  callee(who),callback(func){}
 void click()
  {(callee->*callback)();}
private:
 T *callee;
        void (T::*callback)(void);
};
我就給你一個Function跟我的大名,自己看著辦!酷!

二三這兩種模式在Multithread的系統經常被使用,但Java缺少了關鍵性的function pointer,所以怎麼看都少了點fu.雖然Java沒有function pointer,但利用第二種做法還是可以寫出很有callback fu的API,第一種模式寫的JDBC程式可以改成下面這樣

Interface CallbackStatement {
 String hereIsMyStatement();
 Object[] hereAreMyParameters();
 void letMeKnowIfThereIsAnyProblem(String msg);
}

Interface SQLExecutor() {
 void execute(CallbackStatement cs);
}
這樣勉強算是callback吧,其實Spring的JDBCTemplate就是大量用這種方式來工作的喲

04 12月 2009

病貓

有人跟我抱怨為什麼用Eclipse + m2eclipse deploy web project到tomcat時,老是㑹將servlet-api-XXX.jar跟jsp-api-XXX.jar丢到WEB-INF/lib下,結果tomcat就變成起不來的病貓,可是經我個人反覆測試,pom.xml中的dependency只要有加<scope>provided</scope>,一定不㑹被丟到WEB-INF/lib。

遇到這種見鬼的事情,第一件要做的事當然是...拿乖乖去拜你的電腦(誤

有幾個選擇可以解決

(1)自己砍掉WEB-INF/lib中的servlet-api.jar jsp-api.jar,缺點是每次你有改變dependency時就要再做一次。

(2)將serlvet-api跟jsp-api的dependency的設定移到profile中,然後在project->Java build path->Libraries->Add Library
選server runtime,再選tomcat,將tomcat runtime libraries加入你的project libraries,這樣的缺點是每次用Maven都要記得加 -P。

BTW,乖乖團購有比較便宜嗎?