C#接口是一個讓很多初學者容易迷糊的東西,用起來好象很簡單,定義接口,然後在裡面定義方法, 通過繼承與他的子類來完成具體的實現。但沒有真正認識接口的作用的時候就覺得用接口是多此一舉,當 然你這樣想是絕對錯誤的。在軟件設計中有一個非常重要的原則就是:面向接口編程,依賴與接口或抽象 層。可見接口在真正的開發中是多麼的重要。
在之前C#編程利器之一:類(Class)一文裡介紹了類的相關知識,本文主要介紹OO編程中的另一個重要 知識點--接口。在某種程度上說,接口也是類,一種特殊的類或抽象類。 更准確說接口只包含方法、委 托或事件的簽名。方法的實現是在實現接口的類中完成的[MSDN]。
一、接口的定義
如上MSDN上對接口的定義,接口只包含方法、委托或事件的簽名。這句話用更通俗點的解釋便是,接 口只是負責完成定義的操作,而不去實現具體的細節。如下面的IPlayer接口,它是一個玩游戲的接口, 裡面只是定義了相應的方法,而不帶方法的具體實現,代碼如下:
1/**//// <summary>
2/// 玩游戲接口
3/// </summary>
4public interface IPlayer
5{
6 /**//// <summary>
7 /// 獲取玩家的名字
8 /// </summary>
9 /// <returns>玩家的名字</returns>
10 string GetName();
11
12 /**//// <summary>
13 /// 由Player決定出什麼手勢
14 /// </summary>
15 /// <returns>本接口定義的三個常量之一</returns>
16 string Show();
17}
以上就是一個典型的接口的定義。定義了一個名為IPlayer的接口,內部定義了兩個方法GetName和 Show。除了在接口裡定義方法以外,我們還可以定義屬性、索引及事件等,詳細請查看MSDN上的定義或是 相關書籍,這裡以屬性為例簡單介紹下,在接口裡只能定義不實現,具體的實現是交給其子類去完成的, 那麼屬性應該怎麼定義呢?
通常我們定義屬性如下:
1/**//// <summary>
2/// 定義_Name屬性,並提供get;set屬性訪問器
3/// </summary>
4private string _Name;
5public string Name
6{
7 get { return _Name; }
8 set { _Name = value; }
9}
那麼在接口中又是怎麼定義屬性,並讓其子類去實現呢?如下代碼段:
1/**//// <summary>
2/// 定義接口,並在接口裡定義一名為Name的屬性
3/// </summary>
4public interface IAttribute
5{
6 string Name { get;set;}
7}
8/**//// <summary>
9/// 定義一個類去繼承IAttribute接口,並實現其屬性
10/// </summary>
11public class Component : IAttribute
12{
13 public string Name
14 {
15 get
16 {
17 return "張三";
18 }
19 set
20 {
21 this.Name = value;
22 }
23 }
24}
二、接口的實現
在本文開始部分曾經說過,接口只負責定義,不負責實現,具體的實現是交給他的子類去完成的。 OK ,現在我們就以上面定義的玩游戲的接口IPlayer為例,來簡單的介紹下接口的實現。
就拿我的趣味編程中的玩剪刀石頭布的案例來說吧,爺爺和奶奶從小就教授小孫子各中東西,其中玩 趣味游戲就他們常有的事,可小孫子還小不知道變換,每次都出剪刀,這樣能贏他爺爺嗎?有了這個分析 ,我們可以怎麼做呢?上面定義了接口,我們是不是直接去實現這個接口便OK了。爺爺和小孫子玩游戲, 那麼就定義兩個類去繼承IPlayer接口。代碼如下:
1/**//// <summary>
2/// 出手動作狀態
3/// </summary>
4public class Options
5{
6 public static readonly string JIANDAO = "剪刀";
7 public static readonly string SHITOU = "石頭";
8 public static readonly string BU = "布";
9}
游戲裡只會出現這三種動作狀態,所以我們可以進行封裝,這裡是通過類封裝的,當然我們也可以通 過別的相關技術來封裝,比如在本系列第二篇文章《C#編程利器之二:結構與枚舉(Structure and enumeration)》 裡介紹的結構與枚舉,本例中所出現的這三中不變的狀態完全可以使用結構或枚舉來封 裝,詳細請閱讀上篇文章。下面是定義爺爺(Grandpa)類和孫子(Grandson)類去實現接口(IPlayer) 了。代碼如下:
1/**//// <summary>
2/// 爺爺--玩家之一
3/// </summary>
4public class Grandpa:IPlayer
5{
6 public string GetName()
7 {
8 return "爺爺";
9 }
10
11 public string Show()
12 {
13 Random random = new Random();
14 int i = (int)(random.Next() * 1000) % 3;
15 switch (i)
16 {
17 case 0: return Options.JIANDAO;
18 case 1: return Options.SHITOU;
19 default: return Options.BU;
20 }
21 }
22}
1/**//// <summary>
2/// 孫子--玩家之一
3/// </summary>
4public class Grandson:IPlayer
5{
6 public string GetName()
7 {
8 return "孫子";
9 }
10
11 public string Show()
12 {
13 return Options.JIANDAO;
14 }
15}
如上,我們的GrandPa和GrandSon就實現了接口IPlayer,如下圖示:
三、接口的繼承
關於這點這裡就不作詳細的介紹,只需要記住有這樣一句話就萬歲了:“一個接口可從一個或多個基 接口繼承”。示意性代碼:
1interface IA { }
2interface IB:IA { }
3interface IC : IA, IB { }
4interface ID : IA, IB, IC { }
四、接口的特性
接口除了可以包含方法之外,還可以包含屬性、索引器、事件等,而且這些成員都被定義為公有的。 除此之外,不能包含任何其他的成員,例如:常量、域、構造函數、析構函數、靜態成員。一個類可以直 接繼承多個接口,但只能直接繼承一個類(包括抽象類)。
從類型上來說接口是引用類型的,類似於類,和抽象類的相似之處有三點:
1、不能實例化;
2、包含未實現的方法聲明;
3、派生類必須實現未實現的方法,抽象類是抽象方法,接口則是所有成員(不僅是方法包括其他成員 );
五、接口與回調
通常情況下,我們創建一個對象,並馬上直接去使用它的方法。然而,在有些情況下,希望能在某個 場景出現後或條件滿足時才調用此對象的方法。回調就可以解決這個“延遲調用對象方法”的問題。這個 被調用方法的對象稱為回調對象。
首先創建一個回調對象,然後再創建一個控制器對象,將回調對象需要被調用的方法告訴控制器對象.控 制器對象負責檢查某個場景是否出現或某個條件是否滿足.當此場景出現或此條件滿足時,自動調用回調對 象的方法.示意性代碼如下:
1using System;
2using System.Collections.Generic;
3using System.Text;
4
5namespace CallBack
6{
7 class Program
8 {
9 static void Main(string[] args)
10 {
11 //創建一個控制器對象,將提供給它的回調對象傳入
12 Resolve resolve = new Resolve(new PlayBasketball());
13 resolve.Play();
14
15 resolve = new Resolve(new PlayFootball());
16 resolve.Play();
17 }
18 }
19
20 /**//// <summary>
21 /// 定義一個接口--回調對象
22 /// </summary>
23 public interface IPlayer
24 {
25 void Play();
26 }
27
28 /**//// <summary>
29 /// 籃球
30 /// </summary>
31 public class PlayBasketball:IPlayer
32 {
33 public void Play()
34 {
35 Console.WriteLine("玩籃球");
36 }
37 }
38
39 /**//// <summary>
40 /// 足球
41 /// </summary>
42 public class PlayFootball : IPlayer
43 {
44 public void Play()
45 {
46 Console.WriteLine("玩足球");
47 }
48 }
49
50 /**//// <summary>
51 /// 控制角色--控制器對象
52 /// </summary>
53 public class Resolve
54 {
55 //持有一個接口的引用,通過構造方法初始化
56 private IPlayer player;
57 public Resolve(IPlayer player)
58 {
59 this.player = player;
60 }
61
62 public void Play()
63 {
64 player.Play();
65 }
66 }
67}
關於接口的相關知識點本文就介紹於此,更詳細的學習接口這門功夫請大家查閱相關資料。
出處:http://beniao.cnblogs.com/