介面類似抽象基底類別。 任何實作介面的類別或結構必須實作它的所有成員。
介面無法直接具現化。 其成員是由實作介面的任何類別或結構實作。
介面可以包含事件、索引子、方法和屬性。
介面不包含方法的實作。
類別或結構可以實作多個介面。 類別可以繼承基底類別,也會實作一或多個介面。
根據官方的摘要,今天介紹的介面與昨天的繼承概念相似,不同的地方是介面無法實作,但一個類別能夠實作多個介面。
就好比昨天舉的例子,如果鳥與魚將各自的成員在拆開的話呢?只要有會飛的或會游的都應該實作這些成員呢?所以我們把除了本來的動物外,飛與游都當成一個介面如
interface IAnimal {
void Eat ();
void Sleep ();
}
interface IFly {
void Fly ();
}
interface ISwim {
void Swim ();
}
然後我們用來鳥來當範例,實作他需要的介面
class Bird : IAnimal, IFly {
public void Eat () {
Console.WriteLine ("鳥吃");
}
public void Sleep () {
Console.WriteLine ("鳥睡");
}
public void Fly () {
Console.WriteLine ("鳥飛");
}
}
類別必須實作所有的介面成員,如果沒有去實作則會造成錯誤。
介面無法使用存取層級修飾詞,所有成員都自動定義為 public。
依照慣例,介面名稱需在第一個字母加上 I 前綴。
然而有兩個介面擁有相同名稱的成員時,我們可以這樣寫
class Program {
static void Main (string[] args) {
Test test = new Test ();
test.Print ();
Interface1 interface1 = new Test ();
interface1.Print ();
Interface2 interface2 = new Test ();
interface2.Print ();
Console.ReadKey ();
}
}
interface Interface1 {
void Print ();
}
interface Interface2 {
void Print ();
}
class Test : Interface1, Interface2 {
public void Print () {
Console.WriteLine ("我是 Test 的 Print");
}
void Interface1.Print () {
Console.WriteLine ("我是 Interface1 的 Print");
}
void Interface2.Print () {
Console.WriteLine ("我是 Interface2 的 Print");
}
}
當今天如果想要以 Interface1 的 Print 為主的話,我們需要 Interface1 interface1 = new Test ();
,以基底類別來替換衍生類別。若以介面名稱前綴來實作介面時,無法加入存取層級修飾詞,且可以不用再實作一次給衍生類別,但衍生類別就沒有該成員了,可以動手玩玩看。
介面實作可以是顯式(加前綴)與隱式(不加前綴),可以使實作類別是直接公開介面成員(隱式),還是通過介面來強制轉換成公開(顯式)。
介面也可以繼承,假如我們今天不只一種鳥,而是很多很多種鳥,那麼我們可以在把鳥當成一個介面
Interface IBird : IAnimal, IFly {
void LayingEggs ();
}
鳥介面繼承了動物與飛行介面成員外,還有了自己的下蛋成員,你也可以不增加任何成員,就只是單單繼承了其他的介面。
介面可以說是 C# 的物件導向設計的關鍵要素,它提供與抽象類別相似的功能,也因為昨天說過 C# 目前無法多重繼承,而介面可以支持實作多個介面,再加上現在流行的相依性注入,很多 core 的程式碼都是以 DIP 來撰寫,如果不會介面等觀念的話,看程式碼就會相當的吃力。
介面的使用往往搭配著設計模式,以及依照 SOLID 等原則撰寫,雖然本來是有打算寫,但感覺自己還不夠格寫,都只是略懂略懂,網路上有很多的文章,也歡迎留言一起討論。
參考連結
介面 (C# 程式設計手冊) | Microsoft Docs
SOLID (物件導向設計) - 維基百科,自由的百科全書