[.net 面向對象編程基礎] (16) 接口


[.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.接口和類有什么異同:

異:

  不能直接實例化接口。 

  接口不包含方法的實現。 

  接口可以實現多繼承,而類只能是單繼承。 

  類定義可在不同的源文件之間進行拆分。 

同: 

  接口、類和結構可從多個接口繼承。 

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

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

  一個類可以實現多個接口。

  

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

返回目錄

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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM