2008年5月8日

Inversion of Control 與 DI 的分別

最近突然沒有什麼事,花了一點時間把 Inversion of Control 與 Dependency Injection 的議題搞清楚。

Martin Fowler雖然很久以前就說明了 IoC 是什麼,而 DI 又是什麼,但是網路上的文章還是很多人弄錯,有必要說明一下。這邊的解釋沒有任何新意,完全是別人(多半是 Martin Fowler)已經說明過的。

從前,我們寫command line程式時,會要求使用者按照我們的規定輸入資料。比如:先輸入座號、再輸入分數,如此重複五十次完成一個班級的分數輸入作業。然後,用另外一個命令,顯示所有輸入的內容;萬一有錯,再執行一個命令,這個命令會要求我們輸入一筆座號,再輸入分數,僅修改該座號的分數。這樣的執行步驟,都是我們事先決定的,使用者必須按照順序一個一個來;好一點的程式設計者,會提供一些方式讓人中途離開這個流程(比如ctrl-c)。我們的程式寫起來,就是一個接一個的執行一個個指令,這是以前的作法。這樣的程式,寫起來如下:



for i=1 to 50
print "請輸入座號" : input no
print "請輸入分數" : input score
writeSql "insert score(no, score) values(@1, @2)", no, score
next


進入視窗年代後(是,我說的是 Macintosh 的 Window),程式就不是這樣寫了。基本上我們叫出一個可操作的視窗,然後系統進入一個無窮迴圈(其實不是無窮迴圈,不過先這樣想好了)。使用者透過滑鼠操作,點選座號的文字控制項,輸入座號;再點選分數的文字控制項,輸入分數,再點選送出,完成一個操作。在這種寫作程式的方式下,我們的程式比較像是這樣的模式:


var txtNo:TextInput;
var txtScore:TextInput;
var btnSave:Button;
public function initialize():void{
txtNo=new TextInput();
addChild(txtNo);
txtNo.x=10; txtNo.y=50;
txtNo.addEventListener(focusOut, checkTxtNo);

txtScore=new TextInput();
addChild(txtScore);
txtScore.x=10; txtScore.y=90;
txtScore.addEventListener(focusOut, checkTxtScore);

btnSave=new Button();
addChild(btnSave);
btnSave.x=10; btnSave.y=130; btnSave.label="儲存";
btnSave.addEventListener(click, saveScore);
}

private function checkTxtNo(evt:Event):void{
...
}

...


我們寫的程式,只有在使用者做出對應的動作時,才會被系統呼叫,處理該處理的事情,而不再掌管主要的流程。這種程式寫作方式,也就是把程式執行流程的控制權從程式設計者轉移到背後的框架,所以這種程式的架構方式,我們稱為 Inversion of Control。在這種程式的撰寫中,最常用到的就是Template Pattern。

IoC,還可以說明另一個程式庫特性:所有的 Framework,都是 IoC 的,也就是單獨看你寫完的程式碼而沒有該程式庫的背景知識,我們會無法確定執行的流程。不符合以上條件的,就是 Library。所以,Flex是一個 Framework,pureMVC 是 Framework,as3core 則是 Library。另外許多程式庫,雖宣稱是 Framework,但在這樣的標準下,很快就可以判定其實他們應該是 Library,比如個人最近在研究的 AsWing。

這樣的判定有何用處嗎?有,當你需要快速瞭解一個framework時。把framework中,屬於Library的部分先略過,直接切進核心的執行流程(這裡常出現的關鍵字是:life cycle),你就可以很快的掌握該怎麼使用該framework。

以上就是個人關於 Inversion of Control 的瞭解。至於 Dependency Injection,網路上的說明資料就太多了,不需要我再多做說明。倒是有一點可以提:

Inversion of Control Containers and the Dependency Injection pattern 這邊提到兩種decoupling的作法,第一種就是Dependency Injection,第二種是Service Locator。DI 由Java界率先發難,推廣得很好沒問題,但 Service Locator 呢?有人在用嗎?答案是有,而且正是 .Net Framework 的標準作法,只是改名叫做 Provider。

沒有留言:

張貼留言