[C#]抽象類程式:介面(接口)和抽象類

  • 15470
  • 0

摘要:[C#]抽象類程式:介面(接口)和抽象類

本文將介紹以下內容:

●物件導向(面向對象)思想:多態

●介面(接口)

●抽象類

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

1.概念引入

●什麼是介面(接口)?

介面(接口)是包含一組虛擬方法的抽象類型,其中每一種方法都有其名稱,參數和返回值。介面(接口)方法不能包含任何實現,CLR(公共運行語言)允許介面(接口)可以包含事件屬性索引子(索引器)、靜態方法(Static method)靜態字段(Static field)靜態建構函式(靜態構造函數)以及常數(常量)。但是注意:C#中不能包含任何靜態成員。一個類可以實現多個介面(接口),當一個類繼承某個介面(接口)時,它不僅要實現該介面(接口)的所有方法,還要實現該介面(接口)從其他介面(接口)中繼承的所有方法。

定義介面(接口)方法:


public interface IComparable
    {
        int CompareTo(object o);
    }

    public class TestCls: IComparable
    {
        public TestCls()//建構函式(構造函數)
        {
        } 

        private int _value;
        public int Value
        {
            get { return _value; }
            set { _value = value; }
        } 

        public int CompareTo(object o)
        {

            //使用as關鍵字進行轉型判斷
            TestCls aCls = o as TestCls;
            if (aCls != null)
            {
            //實現抽象方法
            //return _value.CompareTo(aCls._value);
                return 1;
            }
            else
            {
                return 0;
            }
        }
    }

●什麼是抽象類

抽象類提供多個衍生類(派生類)共享基類的公共定義,它既可以提供抽象方法,也可以提供非抽象方法。抽象類不能實例化,必須通過繼承由衍生類(派生類)實現其抽象方法,因此對抽象類不能使用new關鍵字,也不能被密封。如果衍生類(派生類)沒有實現所有抽象方法,則該衍生類(派生類)也必須聲明為抽象類。另外,實現抽象方法由Overriding方法來實現。

定義抽象類方法:


/// 
/// 定義抽象類
/// 
abstract public class Animal
{
    //定義靜態字段
    protected int _id;

    //定義屬性
    public abstract int Id
    {
        get;
        set;
    }

    //定義方法
    public abstract void Eat();

    //定義索引子(索引器)
    public abstract string this[int i]
    {
        get;

        set;
    }
}

/// 
/// 實現抽象類
/// 
public class Dog : Animal
{
    public override int Id
    {
        get { return _id; }
        set { _id = value; }
    }

    public override void Eat()
    {
        Console.Write("Dog Eats.");
    }
    string[] name = new string[10];
    public override string this[int i]
    {
        get
        {
            return name[i];
        }
        set
        {
            name[i] = value;
        }
    }
    
} 

2.相同點和不同點

2.1相同點

          ●都不能被直接實例化,都可以通過繼承實現其抽象方法。

          ●都是物件導向程式的技術基礎,實現了諸多設計模式。

2.2不同點

          ●介面(接口)支持多繼承,抽象類不能實現多繼承。

          ●介面(接口)只能定義抽象規則;抽象類既可以定義抽象規則,還可能提供已實現的成員。

          ●介面(接口)是一組行為規範;抽象類是依個不完全的類,著種家族(族)的概念。

          ●介面(接口)可以用於支持回呼(回調);抽象類不能實現回呼(回調),因為繼承不支持。

          ●介面(接口)只包含方法、屬性、索引子(索引器)、事件的簽名,但不能定義字段和包含實現的方法;抽象類  
            可以定義字段、屬性、包含實現的方法。

          ●介面(接口)可以作用於值類型參考型別(引用類型);抽象類只能作用於參考型別(引用類型)。例如,Struct
            就可以繼承介面(接口),而不能繼承類。

通過相同與不同的比較,我門只能說介面(接口)和抽象類,各有所長,但無優劣。在實際的程式設計中,我們要視具體情況來酌情量才,但是以下的經驗和累積,或許能給大家一些啟示,除了我的一些累積之外,很多來源於經典,我相信經得起考驗。所以在規則與場合中,我們學習這些經典,最重要的是學以致用,當然我將以一家之言博大家之笑,看官請繼續。

2.3規則與場合

          ●請記住,物件導向思想的一個最重要的原則就是:物件導向程式。

          ●藉助介面(接口)和抽象類,23個設計模式中的很多思想被巧妙的實現了,我認為其精隨簡單來說就是:物件導
            向程式。

          ●抽象類應主要用於關係密的的對象,而接口最適合不相關的類提供通用功能。

          ●介面(接口)著種CAN-DO關係類型,而抽線類則偏重於IS-A式的關係。

          ●介面(接口)多定義對象的行為;抽象類多定義對象的屬性。

          ●介面(接口)定義可以使用publicprotectedinternalprivate修飾符,但是幾乎所有的的介面(接口)都 
            定義為public,原因就不必多說了。

          ●介面(接口)不變,是應該考慮的重要因素。所以,在由介面(接口)增加擴展時,應該增加新的介面(接口),
            而不能更改現有介面(接口)。

          ●盡量將介面(接口)設計為功能單一個模組(功能塊),以.NET Framework為例,IDisposableIComparable
            IEquatableIEnumerable等都只包含一個公共方法。

          ●介面(接口)名稱前面的大寫字母"I"是一個約定,正如字段名以下划線開頭一樣,請堅持這些原則。

          ●在介面(接口)中,所有的方法都默認為public。

          ●如果預計會出現版本問題,可以創建"抽象類"。例如,創建了狗(Dog)、雞(Chicken)和鴨(Duck),那麼應該考
            慮抽象動物(Animal)來應對以後可能出現鳳馬牛的事情。而向介面(接口)中添加新成員則會強制要求修改所有
            衍生類(派生類),並重新編譯,所以版本式的問題最好以抽象類來實現。

          ●從抽象類衍生(派生)的非抽象類必須包含繼承的所有抽象方法和抽象存取子(訪問器)的實現。

          ●對抽象類不使用new關鍵字,也不能被密封,原因是抽象類不能實例化。

          ●在抽象方法聲明不能使用staticvirtual修飾符。

3.經典範例

3.1絕對經典

.NET Framework是學習的最好資源,有意識的研究FCL(Framework Class Library)是每個.NET程式設計員必修課程,關於介面(接口)和抽象類在FCL中的使用,我有以下的建議。

          ●FCL對集合類使用了基於介面(接口)的設計,所以請注意System.Collections中關於介面(接口)的設計實現。

          ●FCL對數據流相關類使用了基於抽象類的設計,所以請注意System.IO.Stream類的抽象類設計機制。

3.2別樣小菜

本範例沒有闡述抽象類和介面(接口)在設計模式中的應用,因為那將是另一篇有討論價值的文件,本文著眼與觀念和原則的把握,但是真正的應用來自於具體的需求規範。

轉載至:http://www.cnblogs.com/anytao/archive/2007/04/12/must_net_02.html

 


    /// 
    /// 定義抽象類
    /// 
    public abstract class Animal
    {
        protected string _name;

        //聲明抽象屬性
        public abstract string Name
        {
            get;
        }

        //聲明抽象方法
        public abstract void Show();

        //實現一般方法
        public void MakeVoice()
        {
            Console.WriteLine("All animals can make voice!");
        }
    }
    /// 
    /// 定義介面
    /// 
    public interface IAction
    {
        //定義公共方法
        void Move();
    }
    /// 
    /// 實現介面(接口)與抽象類
    /// 
    //Duck類別繼承至抽象類Animal與介面(接口)IAction
    public class Duck : Animal, IAction
    {
        public Duck(string name)//建構函式(構造函數)
        {
            _name = name;
        }

        //重載抽象方法
        public override void Show()
        {
            Console.WriteLine(_name + " is showing for you.");
        }

        //重載抽象屬性
        public override string Name
        {
            get { return _name;}
        }

        //實現介面(接口)方法
        public void Move()
        {
            Console.WriteLine("Duck also can swim.");
        }

    }
    //Dog類別繼承至抽象類Animal與介面(接口)IAction
    public class Dog : Animal, IAction
    {
        public Dog(string name)//建構函式(構造函數)
        {
            _name = name;
        }
        //重載抽象方法
        public override void Show()
        {
            Console.WriteLine(_name + " is showing for you.");
        }
        //重載抽象屬性
        public override string Name
        {
            get { return _name; }
        }
        //實現介面(接口)方法
        public void Move()
        {
            Console.WriteLine(_name + " also can run.");
        }

    }
    /// 
    /// 實作
    /// 
    class TestAnmial
    {
        static void Main(string[] args)
        {
            //鴨子
            Animal duck = new Duck("Duck");
            duck.MakeVoice();
            duck.Show();
            //狗狗
            Animal dog = new Dog("Dog");
            dog.MakeVoice();
            dog.Show();
            //以介面實作Dog類別
            IAction dogAction = new Dog("A big dog");
            dogAction.Move();
        }
    }

	
4.他山之石
 
正所謂真理是大家看出來的,所以將園子裡有創新性的觀點潛列於此,一是感謝大家的共享,二是完善一家之言的不足,希望能夠將領域形成知識,受用於我,受用於眾。 
 
dunai認為:抽像類是提取具體類的公因式,而接口是為了將一些不相關的類“雜湊”成一個共同的群體。至於他們
在各個語言中的句法,語言細節並不是我關心的重點。 
樺山澗的收藏也很不錯。 
Artech認為:程式碼共用和可擴展性考慮,盡量使用Abstract Class。當然介面(接口)在其他方面的優勢,我認
為也不可忽視。 
shenfx認為:當在差異較大的對象間尋求功能上的共性時,使用介面(接口);當在共性較多的對象間尋求功能上的
差異時,使用抽象類。
最後,MSDN的建議是: 
如果預計要創建組件的多個版本,則創建抽像類。抽像類提供簡單易行的方法來控制組件版本。通過更新基類,所有繼承類都隨更改自動更新。另一方面,介面(接口)一旦創建就不能更改。如果需要介面(接口)的新版本,必須創建一個全新的介面(接口)。如果創建的功能將在大範圍的全異對象間使用,則使用接口。抽像類應主要用於關係密切的對象,而接口最適合為不相關的類提供通用功能。如果要設計小而簡練的功能塊,則使用接口。如果要設計大的功能單元,則使用抽像類。如果要在組件的所有實現間提供通用的已實現功能,則使用抽像類。抽像類允許部分實現類,而接口不包含任何成員的實現。 
 
5. 結論 
 
介面(接口)和抽像類,是論壇上、課堂間討論最多的話題之一,之所以將這個老話題拿出來再議,是因為從我的體會來說,深刻的理解這兩個面向對象的基本內容,對於盤活面向對象的抽象化編程思想至關重要。本文基本概況了接口和抽像類的概念、異同和使用規則,從學習的觀點來看,我認為這些總結已經足以表達其核心。但是,對於面向對象和軟件設計的深入理解,還是建立在不斷實踐的基礎上,Scott說自己每天堅持一個小時用來寫Demo,那麼我們是不是更應該勤於鍵盤呢。對於介面(接口)和抽像類,請多用而知其然,多想而知其奧吧。
 
 
 
 
Copy to ©2007 Anytao.com

我只是個小小的入門者