C#程式設計利器之三:介面(Interface)

iDotNetSpace發表於2009-05-15

     C#介面是一個讓很多初學者容易迷糊的東西,用起來好象很簡單,定義介面,然後在裡面定義方法,通過繼承與他的子類來完成具體的實現。但沒有真正認識介面的作用的時候就覺得用介面是多此一舉,當然你這樣想是絕對錯誤的。在軟體設計中有一個非常重要的原則就是:面向介面程式設計,依賴與介面或抽象層。可見介面在真正的開發中是多麼的重要。

 

      在之前C#程式設計利器之一:類(Class)一文裡介紹了類的相關知識,本文主要介紹OO程式設計中的另一個重要知識點--介面。在某種程度上說,介面也是類,一種特殊的類或抽象類。 更準確說介面只包含方法、委託或事件的簽名。方法的實現是在實現介面的類中完成的[MSDN]。

 

一、介面的定義

     如上MSDN上對介面的定義,介面只包含方法、委託或事件的簽名。這句話用更通俗點的解釋便是,介面只是負責完成定義的操作,而不去實現具體的細節。如下面的IPlayer介面,它是一個玩遊戲的介面,裡面只是定義了相應的方法,而不帶方法的具體實現,程式碼如下:

 1/**////


 2/// 玩遊戲介面
 3///

 4public interface IPlayer
 5{
 6    /**////
 7    /// 獲取玩家的名字
 8    ///

 9    /// 玩家的名字
10    string GetName();
11
12    /**////
13    /// 由Player決定出什麼手勢
14    ///

15    /// 本介面定義的三個常量之一
16    string Show();
17}
     以上就是一個典型的介面的定義。定義了一個名為IPlayer的介面,內部定義了兩個方法GetName和Show。除了在介面裡定義方法以外,我們還可以定義屬性、索引及事件等,詳細請檢視MSDN上的定義或是相關書籍,這裡以屬性為例簡單介紹下,在介面裡只能定義不實現,具體的實現是交給其子類去完成的,那麼屬性應該怎麼定義呢?

 

     通常我們定義屬性如下:

1/**////


2/// 定義_Name屬性,並提供get;set屬性訪問器
3///

4private string _Name;
5public string Name
6{
7    get { return _Name; }
8    set { _Name = value; }
9}
 

     那麼在介面中又是怎麼定義屬性,並讓其子類去實現呢?如下程式碼段:

 1/**////


 2/// 定義介面,並在介面裡定義一名為Name的屬性
 3///

 4public interface IAttribute
 5{
 6    string Name { get;set;}
 7}
 8/**////
 9/// 定義一個類去繼承IAttribute介面,並實現其屬性
10///

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/**////


2/// 出手動作狀態
3///

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/**////


 2/// 爺爺--玩家之一
 3///

 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/**////


 2/// 孫子--玩家之一
 3///

 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    /**////


21    /// 定義一個介面--回撥物件
22    ///

23    public interface IPlayer
24    {
25        void Play();
26    }
27
28    /**////
29    /// 籃球
30    ///

31    public class PlayBasketball:IPlayer
32    {
33        public void Play()
34        {
35            Console.WriteLine("玩籃球");
36        }
37    }
38
39    /**////
40    /// 足球
41    ///

42    public class PlayFootball : IPlayer
43    {
44        public void Play()
45        {
46            Console.WriteLine("玩足球");
47        }
48    }
49
50    /**////
51    /// 控制角色--控制器物件
52    ///

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/http://www.cnblogs.com/  作者 :Beniao

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-598256/,如需轉載,請註明出處,否則將追究法律責任。

相關文章