[.net 物件導向程式設計基礎] (16) 介面

yubinfeng發表於2015-06-08

[.net 物件導向程式設計基礎] (16) 介面

     關於“介面”一詞,跟我們平常看到的電腦的硬體“介面”意義上是差不多的。拿一臺電腦來說,我們從外面,可以看到他的USB介面,COM介面等,那麼這些介面的目的一就是讓第三方廠商生產的外設都有相同的標準,也是提供一個對外通訊或操作的入口。

只是C#的介面除了以上特點之外,還具有一種類似於模板的功能,我們定義一組介面,就像是一個模板。這點和抽象類不同,抽象類是先有子類或都子類的概念,從中抽象出一個類。而介面更像是我們要設計一臺機器,先把這臺機器對外的功能介面列出來,然後再做具體的實現,當然這個說法是站在軟體設計的角度來講的。

1.什麼是介面?

介面就是把隱式公共方法和屬性組合起來,以封裝特定功能的一個集合。

介面簡單理解就是一種約定,使得實現介面的類或結構在形式上保持一致。

介面描述的是可屬於任何類或結構的一組相關功能,所以實現介面的類或結構必須實現介面定義中指定的介面成員。

介面使用interface 關鍵字進行定義,可由方法、屬性、事件、索引器或這四種成員型別的任意組合構成。

介面的名稱,通常使用I開頭(按規範命名很重要)

2、介面的特性

A.介面類似於抽象基類,不能直接例項化介面;介面中的方法都是抽象方法,實現介面的任何非抽象型別都必須實現介面的所有成員:

當顯式實現該介面的成員時,實現的成員不能通過類例項訪問,只能通過介面例項訪問。

當隱式實現該介面的成員時,實現的成員可以通過類例項訪問,也可以通過介面例項訪問,但是實現的成員必須是公有的。

B.介面不能包含常量、欄位、運算子、例項建構函式、解構函式或型別、不能包含靜態成員。

C.介面成員是自動公開的,且不能包含任何訪問修飾符。

D.介面自身可從多個介面繼承,類和結構可繼承多個介面,但介面不能繼承類。

3.介面和抽象類的區別:

   介面用於規範,抽象類用於共性。

   介面中只能宣告方法,屬性,事件,索引器。而抽象類中可以有方法的實現,也可以定義非靜態的類變數。

   抽象類是類,所以只能被單繼承,但是介面卻可以一次實現多個。

   抽象類可以提供某些方法的部分實現,介面不可以。

   抽象類的例項是它的子類給出的。介面的例項是實現介面的類給出的。 

   在抽象類中加入一個方法,那麼它的子類就同時有了這個方法。而在介面中加入新的方法,那麼實現它的類就要重新編寫(這就是為什麼說介面是一個類的規範了)。

   介面成員被定義為公共的,但抽象類的成員也可以是私有的、受保護的、內部的或受保護的內部成員(其中受保護的內部成員只能在應用程式的程式碼或派生類中訪問)。

   此外介面不能包含欄位、建構函式、解構函式、靜態成員或常量。 

   抽象類可以包含一些成員的實現,介面卻不包含成員的實現;抽象類的抽象成員可以被子類實現,而介面的的成員需要實現類完全實現;一個類可能繼承一個抽象類,但是可以實現多個介面。

4.介面和抽象類在設計角度的異同

   上面說了介面和抽象類在表象上或說是形態上的區別,此外介面和抽象類在設計過程中也有很多不同之處,這也就是C#為何設計了抽象類還要設計介面的原因。即他們使用場合的不同。

      第一、類是對物件的抽象;抽象類是對類的抽象;介面是對行為的抽象; 

      第二、如果行為跨越不同類的物件,可使用介面;對於一些相似的物件使用繼承抽象類;

      第三、從設計角度講,抽象類是從子類中發現了公共的東西,泛化出父類,然後子類繼承父類;而介面跟本不知道子類的存在,方法如何實現還不確認,即預先定義。

     在實際專案中,抽象類往往是通過重構產生,除非你事先知道某類有很多子類要實現,從而抽象出抽象類,即自底而上設計。介面則是在專案設計之初就確實要實現那些行為,屬於自頂向下設計。

5.程式碼示例

通過上面的學習,我們知道了抽象類和介面的區別以及他們在設計角度的使用。下面,我們按國際慣例重新設計我們的動物類(Animal)以及他們的子類狗(Dog)、貓(Cat)、羊(Sheep)假如我們事先知道有一種羊“喜羊羊”(PleasantSheep)和一種貓“藍貓”(BlueCat)他們有一個共同的行為就是會說話,這時候,我們肯定會想到給他們的抽象類Animal定義一個抽象方法說話(Speak),哈哈,犯錯了吧,動物都可以講話麼?為了解決這種事例,我們需要用到介面,我們事先知道有一個“講話”這個行為,那麼我就定義一個講話的介面(ISpeak).UML圖如下

 

下面看一下程式碼:

 

  1 /// <summary>
  2 /// 動物類(父類 抽象類)
  3 /// </summary>
  4 abstract class Animal
  5 {
  6     /// <summary>
  7     /// 名字
  8     /// 說明:類和子類可訪問
  9     /// </summary>
 10     protected string name;
 11 
 12     /// <summary>
 13     /// 建構函式
 14     /// </summary>
 15     /// <param name="name"></param>
 16     public Animal(string name)
 17     {
 18         this.name = name;
 19     }
 20 
 21     private int shoutNum = 3;
 22     public int ShoutNum
 23     {
 24         get { return shoutNum; }
 25         set { shoutNum = value; }
 26     }
 27 
 28     /// <summary>
 29     /// 名字(虛屬性)
 30     /// </summary>
 31     public virtual string MyName
 32     {
 33         get { return this.name; }
 34     }
 35 
 36     /// <summary>
 37     /// 叫聲,這個方法去掉虛方法,把迴圈寫在這裡
 38     /// </summary>
 39     public void Shout()
 40     {
 41         string result = "";
 42         for (int i = 0; i < ShoutNum; i++)
 43             result += getShoutSound() + "";
 44 
 45         Console.WriteLine(MyName);
 46         Console.WriteLine(result);
 47     }
 48 
 49     /// <summary>
 50     /// 建立一個叫聲的虛方法,子類重寫
 51     /// </summary>
 52     /// <returns></returns>
 53     public virtual string getShoutSound()
 54     {
 55         return "";
 56     }
 57 }
 58 
 59 /// <summary>
 60 /// 宣告一個介面 ISpeak(講話)
 61 /// </summary>
 62 interface ISpeak
 63 {
 64     void Speak();
 65 }
 66 
 67 /// <summary>
 68 /// 狗(子類)
 69 /// </summary>
 70 class Dog : Animal
 71 {
 72     string myName;
 73     public Dog(string name): base(name)
 74     {
 75         myName = name;
 76     }
 77     /// <summary>
 78     /// 名字(重寫父類屬性)
 79     /// </summary>
 80     public override string MyName
 81     {
 82         get { return "我是:狗狗,我叫:" + this.name; }
 83     }
 84     /// <summary>
 85     /// 叫(重寫父類方法)
 86     /// </summary>
 87     public override string getShoutSound()
 88     {
 89         return "汪!";
 90     }
 91 }
 92 
 93 
 94 /// <summary>
 95 /// 貓(子類)
 96 /// </summary>
 97 class Cat : Animal
 98 {
 99     string myName;
100     public Cat(string name): base(name)
101     {
102         myName = name;
103     }
104     /// <summary>
105     /// 名字(重寫父類屬性)
106     /// </summary>
107     public override string MyName
108     {
109         get { return "我是:貓咪,我叫:" + this.name; }
110     }
111     /// <summary>
112     /// 叫(重寫父類方法)
113     /// </summary>
114     public override string getShoutSound()
115     {
116         return "喵!";
117     }
118 }
119 
120 /// <summary>
121 /// 藍貓(子類)
122 /// 繼承 Cat和介面ISpeak
123 /// </summary>
124 class BlueCat : Cat,ISpeak
125 {
126     string myName;
127     public BlueCat(string name) : base(name)
128     {
129         myName = name;
130     }
131     /// <summary>
132     /// 名字(重寫父類屬性)
133     /// </summary>
134     public override string MyName
135     {
136         get { return "我是:藍貓,我叫:" + this.name; }
137     }
138 
139     /// <summary>
140     /// 實現介面ISpeak的成員Speak
141     /// </summary>
142     public void Speak()
143     {
144         Console.WriteLine("我會說人話:“你好,我叫:" + this.name + "~~~”");
145     }
146 }
147 
148 
149 /// <summary>
150 /// 羊(子類)
151 /// </summary>
152 class Sheep : Animal
153 {
154     string myName;
155     public Sheep(string name): base(name)
156     {
157         myName = name;
158     }
159     /// <summary>
160     /// 名字(重寫父類屬性)
161     /// </summary>
162     public override string MyName
163     {
164         get { return "我是:羊羊,我叫:" + this.name; }
165     }
166     /// <summary>
167     /// 叫(重寫父類方法)
168     /// </summary>
169     public override string getShoutSound()
170     {
171         return "咩!";
172     }
173 }
174 
175 /// <summary>
176 /// 喜羊羊(子類)
177 /// 繼承 Sheep和介面ISpeak
178 /// </summary>
179 class PleasantSheep : Sheep, ISpeak
180 {
181     string myName;
182     public PleasantSheep(string name) : base(name)
183     {
184         myName = name;
185     }
186     /// <summary>
187     /// 名字(重寫父類屬性)
188     /// </summary>
189     public override string MyName
190     {
191         get { return "我是:喜羊羊,我叫:" + this.name; }
192     }     
193     /// <summary>
194     /// 實現介面ISpeak的成員Speak
195     /// </summary>
196     public void Speak()
197     {
198         Console.WriteLine("我會說人話:“你好,我叫:" + this.name + "~~~”");
199     }
200 }

呼叫一:

//喜羊羊來了出場了
Animal pleasantSheep = new PleasantSheep("最帥喜羊羊");
pleasantSheep.Shout();
ISpeak IPleasantSheepSpeak= new PleasantSheep("最帥喜羊羊");
IPleasantSheepSpeak.Speak();
Console.ReadLine();
//結果如下:
//我是:喜羊羊,我叫:最帥喜羊羊
//咩!!咩!!咩!!
//我會說人話:“你好,我叫:最帥喜羊羊~~~”

呼叫二:

//藍貓出場了
Animal blueCat = new BlueCat("最美藍貓");
blueCat.Shout();
ISpeak IBlueCatSpeak = new PleasantSheep("最美藍貓");
IBlueCatSpeak.Speak();
Console.ReadLine();
//結果如下:
//我是:藍貓,我叫:最美藍貓
//喵!!喵!!喵!!
//我會說人話:“你好,我叫:最美藍貓~~~”

 

6.要點:

A.介面簡單理解就是一種約定,使得實現介面的類或結構在形式上保持一致

B.介面的類可以實現方法、屬性、事件、索引器這四種型別,不能實現委託。後面要說,委託是一種型別,而介面成員非型別。

C.介面中的成員用來定義物件之間通訊的契約,指定介面中的成員為私有或保護沒有意義。它們預設為公有。

D.介面可以繼承多個介面,但不能繼承類

E.類可以繼承多個介面,但不能繼

F.介面和類有什麼異同:

異:

  不能直接例項化介面。 

  介面不包含方法的實現。 

  介面可以實現多繼承,而類只能是單繼承。 

  類定義可在不同的原始檔之間進行拆分。 

同: 

  介面、類和結構可從多個介面繼承。 

  介面類似於抽象基類:繼承介面的任何非抽象型別都必須實現介面的所有成員。 

  介面可以包含事件、索引器、方法和屬性。 

  一個類可以實現多個介面。

  

============================================================================================== 

返回目錄

 <如果對你有幫助,記得點一下推薦哦,有不明白的地方或寫的不對的地方,請多交流>
 

==============================================================================================  

相關文章