抽象類及介面詳解

小世界的野孩子發表於2019-07-19

一、前言

  在上一節中我們講到抽象類和介面之間的異同,我們一起回顧下其異同。

  同:

  1、都不可以被例項化

  2、都含有宣告但未實現的方法

  3、都可以被繼承

  4、其子類必須實現其宣告未實現的方法

  異:

  1、抽象類是多繼承,介面是單繼承

  2、抽象類可以包含實現的方法,介面不能包含實現的方法

  3、介面支援回撥,抽象類不支援

  4、抽象類更多的定義在一些類關係緊密的類間,介面則定義在實現其某一種功能之間

  抽象類和介面的異同我們再次熟悉了一遍,今天我們主要講的是抽象類和介面使用場景及詳講抽象類的使用方法及介面的使用方法

二、使用場景

  抽象類、普通類、介面。我們到底什麼時候使用哪一個呢?這就很頭痛了,不是一直使用一個就是好的。每一個都有每一個的使用場景。下面我們看看到底啥事時候用啥東西吧。

  我們現在假設一個場景,現在需要設計一個程式,用來描述各個動物的一些生活習性,這裡我們就有豬、貓、狗。

  不使用抽象類也不使用介面。我們設計他們三個的各個習性,就是豬的類裡面就包含自己的習性,貓類裡面包含自己的習性,狗類裡面包含自己的習性。如果各個習性較多但也有相同的。這樣的類看起來非常的冗餘。

  我們加入抽象類(設計實現大的功能單元),定義一個抽象類-哺乳動物類,其中定義了共同的習性,走路的方法,呼吸的方法,繁衍下一代的方法。但是叫聲不一樣。我們又宣告一個叫聲的方法不實現(抽象方法)。這樣再我們去定義豬類或者狗類的時候只需要寫出不一樣的地方即可。這樣看起來程式碼也簡潔,清楚

  我們現在改用介面(設計實現小而簡練的功能),我們把這些動物可以做什麼列出來,然後統一使用介面去定義公共的。比如叫聲,行走。這些功能,我們就可以使用介面來定義宣告。然後繼承再去實現。

到了這裡,我們總結下到底我們編寫程式為什麼需要使用抽象類呢?為什麼需要使用介面呢?單一用一個普通的類不好嗎?簡單又容易。其實不然。存在即合理。我們一起看看到底為什麼要使用吧

  為什麼使用抽象類?

  抽象類往往用來表徵對問題領域進行分析、設計中得出的抽象概念,是對一系列看上去不同,但是本質上相同的具體概念的抽象`。這樣來說如果一個類設計就是為了給其他類繼承的,它代表一類物件所具有的公共屬性或方法,我們就使用抽象類。就像上門的這個例子,把一些動物共同的屬性或者方法提取出來,定義一個抽象類。程式碼變的易懂,程式碼冗餘減少,變得簡潔明瞭。實現了程式碼複用性。

  那麼為什麼使用介面呢?

  通俗點講就是為了降低程式碼的耦合度。介面的意義在於抽象,不拘細節,從而使同類事物在在同一高度具有通用性及可替代性。上面的例子來講,規定好了這個叫聲這個方法,那麼繼承的就去實現這個叫聲方法就好了。如果某天加入了一個新的動物,這樣我們也不需要修改其他的任何方面,僅繼承一下介面修改本身即可,不需要修改或改變其他的類或者介面。系統的靈活性增加了。

 

  這裡可能會有個問題了。既然有了抽象類為什麼還要用介面呢?這會不會有點多餘?

  答案肯定是不會的。那麼有了抽象類為什麼還要使用介面呢?我們看看抽象類和介面的異同就很快能明白了。

  1、介面提供的事統一的行為規範,供其他呼叫,而抽象類具有介面的特性同時還可以有自己的具體實現

  2、抽象類只能有一個父類,可以實現多個介面

 

  那麼我們如何使用抽象類和介面呢?

三、抽象類及介面使用

  就拿我們上面舉的那個例子來編寫一段程式碼:

    /// <summary>
    /// 叫聲的介面定義
    /// </summary>
    public interface ICry
    {
        string Cry();
    }

    /// <summary>
    /// 說話的介面定義
    /// </summary>
    public interface ISay
    {
        string Say();
    }

 
    /// <summary>
    /// 動物抽象的抽象類
    /// </summary>
    public abstract class Animale
    {
        /// <summary>
        /// 包含的實現了的方法、呼吸、走路
        /// </summary>
        /// <returns></returns>
        public static string Breathe()
        {
            return "呼吸一樣";
        }

        public static string Run()
        {
            return "走路一樣";
        }

        /// <summary>
        /// 未實現的抽象方法睡覺方法
        /// </summary>
        /// <returns></returns>
        public abstract  string Sleep();
    }

    
    /// <summary>
    /// 普通的類  繼承了抽象類及兩個介面
    /// </summary>
    public class Dog: Animale,ICry, ISay
    {
        /// <summary>
        /// 實現重寫抽象方法睡覺
        /// </summary>
        /// <returns></returns>
        public override  string Sleep() { return "睡覺"; }

       /// <summary>
       /// 實現叫聲介面方法
       /// </summary>
       /// <returns></returns>
        public  string Cry() { return "旺旺"; }

        /// <summary>
        /// 實現說話介面方法
        /// </summary>
        /// <returns></returns>
        public string Say() { return "說話"; }

    }

 

  在上面的程式碼中,我們列舉出了介面的定義及抽象類、抽象方法的定義及使用。在最下面一個普通類中,我們繼承了一個抽象類及兩個介面,可以實現多個介面但是隻能有一個抽象父類。如果繼承兩個抽象類的話會報錯的。

  抽象類關鍵字--abstract

  介面關鍵字--interface

 

四、擴充套件延伸(密封類)

  講到抽象類,我們也可以一起看看密封類,密封類不能作為基類,禁止派生。如果重寫了某些功能會導致編譯錯誤或者為了防止第三方進行擴充套件重寫,這個時候我們就可以使用到密封類。

  重點注意

    1、密封類中不能包含虛方法(Virtual)和抽象方法(abstract)。因為密封類是不能被繼承的也就沒有派生類,就不具備實現抽象方法和虛方法的機會。

    2、在使用密封類(sealed)的時候,密封類將限制它的使用,現在及未來都將受到影響

    3、如果例項方法包含了sealed修飾符,那麼它也必須包含override修飾符,其父類方法必須包含virtual修飾符

     /// <summary>
    /// 普通動物類
    /// </summary>
    public  class Animals
    {
        /// <summary>
        /// 動物的叫聲方法,因為其派生類重寫了次方法,所以必須使用virtual修飾符
        /// </summary>
        /// <returns></returns>
        public virtual  string Cry() {
            return "叫聲";
        }
    }

    /// <summary>
    /// 動物狗類密封類,無法產生派生類,不能作為基類,繼承了動物類
    /// </summary>
    public sealed class Dog : Animals
    {
        /// <summary>
        /// 重寫了動物叫的方法,同時標記為了密封方法
        /// </summary>
        /// <returns></returns>
        public  override  sealed   string Cry()
        {
            return "旺旺";
        }
    }

  在使用密封類的時候我們需要考慮的因素需要更加的全面,更加的謹慎,以防後面重新推翻重寫。每個東西都沒有絕對的好,只有你用的恰到好處。多思考多選擇才是智者。

總結

                    c#基礎知識詳解系列

歡迎大家掃描下方二維碼,和我一起學習更多的C#知識

相關文章