抽象類和介面的區別、使用和選擇

来源:http://www.cnblogs.com/Brake/archive/2016/04/02/5348445.html
-Advertisement-
Play Games

不談抽象類可以有實現等語法糖的問題,本文主要講在語義層面抽象類和介面的本質區別、以及使用以及選擇。 一、介紹 抽象類,首先是個類,類是對現實世界中對象的建模模型,抽象類是對類整體的抽象描述,包含方法,以及屬性。介面是對類某特性行為的抽象。 對抽象類的繼承才是Is-A的關係,對介面的實現,則是“有沒有 ...


不談抽象類可以有實現等語法糖的問題,本文主要講在語義層面抽象類和介面的本質區別、以及使用以及選擇。

 一、介紹

抽象類,首先是個類,類是對現實世界中對象的建模模型,抽象類是對類整體的抽象描述,包含方法,以及屬性。介面是對類某特性行為的抽象。

對抽象類的繼承才是Is-A的關係,對介面的實現,則是“有沒有”的關係。比如鳥和飛機都有飛行這個特性,這個時候可以把飛行這個特性設計為介面:IFly。然後再讓Airplane和Bird實現IFly這個介面,這樣Airplane和Bird則擁有了飛行這個屬性。

接下來飛機可能有多種,鳥也有多種,他們飛行的方法完全不同,這樣就可以把Airplan和Bird設計成抽象類,讓不同的飛機和鳥進行繼承。

類圖:

代碼:

public abstract class AbstractAirplane : IFly
{
    public void Fly()
    {
        this.PrepareToFly();
        this.Step1();
        this.Step2();
    }

    private void PrepareToFly()
    {
    }

    protected abstract void Step1();

    protected abstract void Step2();

}
public abstract class AbstractBird : IFly
{
    public void Fly()
    {
        this.PrepareToFly();
        this.Step1();
        this.Step2();
    }

    private void PrepareToFly()
    {
    }

    protected abstract void Step1();

    protected abstract void Step2();

}

在上面的設計中,IFly定義了飛的行為:

  1. AbstractAirplane是實現了該行為,並且定義了飛機飛行的模型,PrepareToFly,Step1,Step2。由於不同飛機的Step1和Step2各不相同,所以定義為Abstract,讓子類自己實現
  2. AbstractBird實現了該行為,並且定義了鳥的飛行模型,PrepareToFly,Step1,Step2。由於不同鳥的Step1和Step2各不相同,所以定義為Abstract,讓子類自己實現

上面的例子可以看出,抽象類一種模版式的設計,介面是一種行為規範。

模版式設計:如果共用部分要修改,比如上圖中的PrepareToFly,則只需要修改共用部分,不需要修改其他,對於抽象類來說,如果要增加方法,可以直接操作父類,子類可以不知情。

行為規範:如果介面要變更,實現這個介面的類都要修改。

二、介面與抽象類的選擇

現實中門有兩個方法Open(), Close(),定義方式分別如下所示:

使用介面方式定義門:

 interface IDoor
    {
        void Open();

        void Close();
    }

 

使用抽象類方式定義門:

 abstract class AbstractDoor
    {
        public abstract void Open();

        public abstract void Close();
    }

 

 

剛開始一切都OK,但是隨著用戶需求的發展,要給門加入報警(Alarm)功能,現在怎麼做?

  1. 把Alarm放入AbstractDoor中,這樣所有繼承自這個類的門都會有Alarm功能,但是並不是所有的門都有報警功能,這樣違反了liskov替換原則
  2. 把Alarm放入IDoor介面中,需要Alarm的門都實現這個介面,那麼需要報警的門得同時實現Open和Close功能,其實有些報警的門不一定需要Open和Close功能,

分析:

從上面可以看出,Open和Close是一個門的固有屬性,Alarm屬於門的延伸附加行為,最好的解決辦法是針對Alarm單獨設計一個介面:

public interface IAlarm 
    {
        void Alarm();
    }

 

普通門的實現:

  public class NormalDoor : AbstractDoor
    {
        public override void Open()
        {
        }

        public override void Close()
        {
        }
    }

 

具有報警功能的門的實現:

 public class AlarmDoor : AbstractDoor,IAlarm
    {
        public override void Open()
        {
        }

        public override void Close()
        {
        }

        public void Alarm()
        {
        }
    }

 

只能報警的設備的實現:

 public class AlarmDevice : IAlarm
    {
        public void Alarm()
        {
        }
    }

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 作為一個菜鳥,剛開始用java連接sqlserver的時候,用的時間不短, 可以說解決了一個又出現一個,所以我覺得有必要把我的經驗分享給大家。 (因為我踩了大部分的坑) 第一個坑:載入驅動。java要連接資料庫就需要驅動,我們去網上下載一個 sqljdbc.jar就行了。下載後該怎麼做呢。 這個時候 ...
  • 這篇文章有點深度,可能需要一些Lucene或者全文檢索的背景。由於我也很久沒有看過Lucene了,有些地方理解的不對還請多多指正。 更多內容 "還請參考整理的ELK教程" 關於Term Vectors 額,對於這個專業辭彙,暫且就叫做詞條向量吧,因為實在想不出什麼標準的翻譯。說的土一點,也可以理解為 ...
  • 原創,未經允許,禁止轉載!!! 分析依據:先載入的不能直接調用後載入的,因為後載入的並不存在無法被使用 後載入的能直接使用先載入的,因為先載入的已存在可以被使用比如:靜態方法先於實例變數,所以靜態方法直接調用實例變數就不行,因為實例變數還不在記憶體中,如下列代碼: 以此為依據使用debug得到分析結論 ...
  • 重載*運算符為友元函數。 ...
  • Filter被稱為過濾器或者攔截器,基本功能就是對調用servler過程的攔截,在servlet進行響應和處理前後實現一些特殊功能。其實,Filter過濾器就是一個實現了javax.servlet.Filter介面的類,在javax.servlet.Filter介面中定義了3個方法: init(Fi ...
  • 一、變數和常量 定義 let 定義常量,一經賦值不允許再修改 var 定義變數,賦值之後仍然可以修改 自動推導 Swift能夠根據右邊的代碼,推導出變數的準確類型 通常在開發時,不需要指定變數的類型 如果要指定變數,可以在變數名後使用:,然後跟上變數的類型 重要技巧:Option + Click 可 ...
  • 這個問題讓我糾結了幾個小時,剛開始還以為是JS有問題,一直排查排查,,最後發現,是thinkphp3.2.3把JS正則的反斜杠\過濾掉了,導致JS正則失效,比如\d{4},解析出來變成了d{4} 解決辦法是可以用兩個反斜杠\\,比如\d{4}寫成 \\d{4}即可 ...
  • 效果: 需求和分析: 1.點擊TreeView中的節點,Listview中顯示相應的電視節目,其中節目的信息都儲存在xml文件中(IO的應用) 2.在“所有電臺”中選中節點右擊可進行添加到“我的電臺”,同時在”我的電臺“也可進行刪除,在你退出後,系統會把你選擇的”我的電臺“中的記錄記錄,在你再次打開 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...