2008年7月13日 星期日

關於Interface

『我不太曉得何時該用Interface』最近一位後進沮喪地這麼跟我說著。當下我只是安慰著他『多用幾次就會了解了』(實際上也是如此),但想起自己當初也曾為了Interface這個奇怪的型別而困惑,因此決定寫一篇文章,期盼能夠對後進同好能有所幫助。

一切要由Lauguage實做的特性說起。一般Language於實做時,對於型別的檢查可分為以下幾種類型:
  • Statically typed language:語言的型別檢查發生於compile time,大部份的statically typed language compiler要求使用者在使用變數前須事先宣告型別。例如:Java、C、C++、C#,好處是多數語法上的錯誤,能夠於早期發現,以及程式執行上更有效率。
  • Dynamically typed language:相對於Statically typed language,語言的型別檢查發生於run time,於第一次指定變數值時,compiler(or interpreter)始決定變數型別。例如:PHP、Perl、Python,好處是使用上具有彈性。
  • Strongly typed language:語言於執行期,其型別不可隨意更改,例如:一個儲存integer的變數,無法用於儲存字串,Java,C,Python等語言皆是。
  • Weakly typed language:相對於Strongly typed language,變數的型別可勿略,例如於PHP中,我們可以將字串'12'和'3'concate在一起,最後再把'123'當作整數123來進行數字運算。
Interface的使用和Lauguage的Statically typed有關,起因於compiler於compile time要求型別的檢查。以下以一個例子說明會較清楚,假定有一要求傳入一個型態為SomeType參數的SomeMethod函式:
void SomeMethod( SomeType inputObject ) {
inputObject.DoSomething();
}
class SomeType {
public void DoSomething() {
//DomSomething implement
}
public void DoOther(){
//DomOther implement
}
}
因為型別檢查,compiler已確定inputObject 確實為型別SomeType,故我們能很放心地於SomeMethod中執行 inputObject.DoSomething() ,而不必擔心inputObject是否已定義了DoSomething()。但SomeMethod這個函式似乎不怎麼好用,因為它要求的參數型別固定,我們無法傳入其它型別的參數,接觸過物件導向Programming的人,應該很快可以想到,我們可以使用繼承的方式,從SomeType衍生出子類別,而此類別的物件,亦能用於呼叫SomeMethod:
class SomeTypeChild extends SomeType {
public void overrides DoSomething();
}
SomeType obj = new SomeTypeChild();
SomeMethod( obj );

類別繼承的好處是,我們可以繼承父類別既有的介面(interface)和實做(implement),若今日我不想繼承SomeType的實做部份,但又想使用SomeMethod呢?又或著我只想繼承SomeType的DoSomething介面,因為SomeMethod中,只需要使用到SomeType的DoSomething?這時Interface的功用就突顯出來了,我們可以改變SomeType的宣告,接受一個有DoSomething介面的物件:
void SomeMethod( InterfaceSomeType inputObject ) {
inputObject.DoSomething();
}
interface InterfaceSomeType {
DoSomething()
}

接下來,只要是繼承了InterfaceSomeType,而有DoSometing介面的型別,皆可用於SomeMethod的參數呼叫,而不用繼承原來SomeType的實做部份,和SomeMethod中不需要用到的DoOther部份。

介面繼承(或介面實做)是類別間的約定,實做該介面的類別『同意』並『保證』要提供介面中所定義到的method和property。由以上的簡單例子,我們可以了解到Interface可以讓我們專注於物件的介面,而不須牽涉到到類別的實做。

下篇,Interface的應用:Dependency Inversion

沒有留言: