介面可以視為只包含抽象成員的一種特殊類別,它只定義成員的介面規格,成員內容則由實作介面的衍生類別根據自身需求提供專屬的實作。介面最大的好處在於將方法成員的規格與實作分開,解決了類別繼承所造成的問題。
繼承機制儘管威力強大,卻相對的衍生出其他的問題,整個繼承關係裏,衍生類別同時被允許存取基礎類別public以及protected層級的相關成員,當繼承架構日益複雜,基礎類別的修改,往往對大量的衍生類別形成不同程度的影響,造成大型系統日後演進的因難,同時降低系統擴充的彈性。
介面將成員規格與實作分開,將類別公用介面從實作中抽離出來,成為獨立不含方法實作的純抽象類別,因此當你定義一個繼承介面的衍生類別,只需遵守方法的宣告語法,再自行定義專屬的方法實作,如此一來即可避免基礎類別與衍生類別之間因為繼承所帶來的問題,另外一方面,由於繼承介面類別可以完全自由實作介面定義的方法內容,在某種程度上亦達到了多型的目的。
接下來從介面的定義開始,討論介面的實作與繼承,說明如何透過介面解決上述繼承所帶來的問題。
定義與使用介面
介面的宣告與類別相當類似,語法如下:
關鍵字 interface 表示目前所定義的是一個介面型別,Iinterfacename 則是介面的名稱,大括弧的介面內容包含功能規格定義。
由於介面本身需由外部類別實作其所有方法,因此所有介面方法一律均為 public 層級,不需使用存取修飾詞,當你使用存取修飾詞於方法宣告時,將會產生修飾詞無效的編譯錯誤。
實作介面的類別必須實作其所有方法成員,也就是必須表現介面所有的行為,即使沒有實作其內容,還是必須在實作類別裏,定義介面的方法。

上圖左邊是一個包含兩個方法成員定義的介面 A ,由於這是一個介面,因此其中的方法成員只定義而沒有任何實作內容,右邊則是實作此介面的兩個類別: B 與 C 。
類別 B 在功能面上,只需提供介面 A 方法成員 aMethod 的實作,但是由於其實作了介面,因此必須同時定義 bMethod ,即便只是定義此方法無任何實作內容,類別 C 亦同時實作了介面 A 與其所有成員。來看以下的程式碼,其中建立一個介面型別 IMeasure:
Length 、 Area 以及Volume 是三個介面方法規格,後續實作此介面的類別必須依據這裏的定義,根據類別的需求,完成三個方法的內容實作。
類別 Square 實作 IMeasure 介面,此類別實作三個介面定義的方法成員 Length 、Area 以及 Volume,最後建立程式測試類別的功能:
其中建立 Square 物件實體 square,然後引用實作介面的方法成員,執行程式嗎將會輸出實作的結果。
此範例說明介面的建立與類別實作,僅輸出提示訊息,並沒有實作真正有意義的內容,方便我們將注意力集中在了解如何使用介面的議題上。
底下列舉幾項介面設計與實作的要點:
繼承機制儘管威力強大,卻相對的衍生出其他的問題,整個繼承關係裏,衍生類別同時被允許存取基礎類別public以及protected層級的相關成員,當繼承架構日益複雜,基礎類別的修改,往往對大量的衍生類別形成不同程度的影響,造成大型系統日後演進的因難,同時降低系統擴充的彈性。
介面將成員規格與實作分開,將類別公用介面從實作中抽離出來,成為獨立不含方法實作的純抽象類別,因此當你定義一個繼承介面的衍生類別,只需遵守方法的宣告語法,再自行定義專屬的方法實作,如此一來即可避免基礎類別與衍生類別之間因為繼承所帶來的問題,另外一方面,由於繼承介面類別可以完全自由實作介面定義的方法內容,在某種程度上亦達到了多型的目的。
接下來從介面的定義開始,討論介面的實作與繼承,說明如何透過介面解決上述繼承所帶來的問題。
定義與使用介面
介面的宣告與類別相當類似,語法如下:
interface Iinterfacename
{
// interface 規格定義 …
}
關鍵字 interface 表示目前所定義的是一個介面型別,Iinterfacename 則是介面的名稱,大括弧的介面內容包含功能規格定義。
由於介面本身需由外部類別實作其所有方法,因此所有介面方法一律均為 public 層級,不需使用存取修飾詞,當你使用存取修飾詞於方法宣告時,將會產生修飾詞無效的編譯錯誤。
實作介面的類別必須實作其所有方法成員,也就是必須表現介面所有的行為,即使沒有實作其內容,還是必須在實作類別裏,定義介面的方法。

上圖左邊是一個包含兩個方法成員定義的介面 A ,由於這是一個介面,因此其中的方法成員只定義而沒有任何實作內容,右邊則是實作此介面的兩個類別: B 與 C 。
類別 B 在功能面上,只需提供介面 A 方法成員 aMethod 的實作,但是由於其實作了介面,因此必須同時定義 bMethod ,即便只是定義此方法無任何實作內容,類別 C 亦同時實作了介面 A 與其所有成員。來看以下的程式碼,其中建立一個介面型別 IMeasure:
interface IMeasure { void Length(); void Area(); void Volume(); }
Length 、 Area 以及Volume 是三個介面方法規格,後續實作此介面的類別必須依據這裏的定義,根據類別的需求,完成三個方法的內容實作。
class Square : IMeasure
{
public void Length()
{
Console.WriteLine("實作Length() 方法");
}
public void Area()
{
Console.WriteLine("實作Area() 方法");
}
public void Volume()
{
Console.WriteLine("實作Volume() 方法");
}
}
類別 Square 實作 IMeasure 介面,此類別實作三個介面定義的方法成員 Length 、Area 以及 Volume,最後建立程式測試類別的功能:
class Program { static void Main(string[] args) { Square square = new Square(); square.Length(); square.Area(); square.Volume(); Console.ReadLine(); } }
其中建立 Square 物件實體 square,然後引用實作介面的方法成員,執行程式嗎將會輸出實作的結果。
實作 Length() 方法 實作 Area() 方法 實作 Volume() 方法
此範例說明介面的建立與類別實作,僅輸出提示訊息,並沒有實作真正有意義的內容,方便我們將注意力集中在了解如何使用介面的議題上。
底下列舉幾項介面設計與實作的要點:
- 分開方法的定義與實作:介面抽離方法的定義與實作,你可以將其視為一種完全只有抽象方法的純抽象類別。
- 避免繼承架構的相依性:介面最大的好處在於避免繼承架構關系裏,基礎類別與衍生類別之間緊密的相依性,提供最大的設計彈性。
- 公開所有成員:所有的介面方法成員均只包含方法名稱,且一律為 public 存取層級。
- 實作所有介面成員:繼承介面的衍生類別必須實作所有的介面成員,你可以實作一個不包含任何內容的方法,避免編譯錯誤,但是無論如何,衍生類別一定要完成所有的介面方法實作。
沒有留言:
張貼留言