SOLID 設計原則

来源:http://www.cnblogs.com/huangenai/archive/2016/12/25/6219475.html
-Advertisement-
Play Games

SOLID 原則基本概念: 程式設計領域, SOLID (單一功能、開閉原則、里氏替換、介面隔離以及依賴反轉)是由羅伯特·C·馬丁在21世紀早期 引入的記憶術首字母縮略字,指代了面向對象編程和麵向對象設計的五個基本原則。當這些原則被一起應用時,它們使得一個程式員開發一個容易進行軟體維護和擴展的系統變 ...


SOLID 原則基本概念:

程式設計領域, SOLID (單一功能、開閉原則、里氏替換、介面隔離以及依賴反轉)是由羅伯特·C·馬丁在21世紀早期 引入的記憶術首字母縮略字,指代了面向對象編程和麵向對象設計的五個基本原則。當這些原則被一起應用時,它們使得一個程式員開發一個容易進行軟體維護和擴展的系統變得更加可能SOLID被典型的應用在測試驅動開發上,並且是敏捷開發以及自適應軟體開發的基本原則的重要組成部分。

 

[S] Single Responsibility Principle (單一功能原則)

單一功能原則 :單一功能原則 認為對象應該僅具有一種單一功能的概念。

換句話說就是讓一個類只做一種類型責任,當這個類需要承擔其他類型的責任的時候,就需要分解這個類。在所有的SOLID原則中,這是大多數開發人員感到最能完全理解的一條。嚴格來說,這也可能是違反最頻繁的一條原則了。單一責任原則可以看作是低耦合、高內聚在面向對象原則上的引申,將責任定義為引起變化的原因,以提高內聚性來減少引起變化的原因。責任過多,可能引起它變化的原因就越多,這將導致責任依賴,相互之間就產生影響,從而極大的損傷其內聚性和耦合度。單一責任,通常意味著單一的功能,因此不要為一個模塊實 現過多的功能點,以保證實體只有一個引起它變化的原因。

                                                   

namespace SOLID
{
    public class Users
    {
        /// <summary>
        /// 支付
        /// </summary>
        public void Pay(){}

        /// <summary>
        /// 資料庫操作
        /// </summary>
        public void DataAccess(){}

        /// <summary>
        /// 日誌操作
        /// </summary>
        public void Logger(){}
    }
}

在這個用戶類中有這三個功能:1.支付邏輯,2資料庫邏輯,3.日誌操作。如果將這三個功能結合在一個類中,可能會出現修改部分代碼時會破壞其他的部分。多個功能也使這個用戶類難以理解,降低了內聚性。所以最好就是將這個類分離為三個分離的類,每個類僅僅有一個功能。

namespace SOLID
{
    /// <summary>
    /// 資料庫操作
    /// </summary>
    class DataAccess { }
/// <summary> /// 日誌 /// </summary> class Logger { }
/// <summary> /// 支付 /// </summary> class Pay { } }

 

[o] Open Close Principle (開閉原則)

開閉原則(ocp) 認為“軟體體應該是對於擴展開放的,但是對於修改封閉的”的概念。

軟體實體應該是可擴展,而不可修改的。也就是說,對擴展是開放的,而對修改是封閉的。這個原則是諸多面向對象編程原則中最抽象、最難理解的一個。
對擴展開放,意味著有新的需求或變化時,可以對現有代碼進行擴展,以適應新的情況。
對修改封閉,意味著類一旦設計完成,就可以獨立完成其工作,而不要對類進行任何修改。
可以使用變化和不變來說明:封裝不變部分,開放變化部分,一般使用介面繼承實現方式來實現“開放”應對變化,說大白話就是:你不是要變化嗎?,那麼我就讓你繼承實現一個對象,用一個介面來抽象你的職責,你變化越多,繼承實現的子類就越多。

                                                    

    abstract class DataAccess
    {
        public abstract void OpenConnection();
        public abstract void CloseConnection();
        public abstract void ExecuteCommand();
    }

    /// <summary>
    /// SQL
    /// </summary>
    class SqlDataAccess : DataAccess
    {
        /// <summary>
        /// 打開SQL資料庫
        /// </summary>
        public override void OpenConnection(){}
        /// <summary>
        /// 關閉Sql數據連接
        /// </summary>
        public override void CloseConnection(){}
        /// <summary>
        /// 執行Sql數據命令
        /// </summary>
        public override void ExecuteCommand(){}
    }
    
    /// <summary>
    /// ORACLE
    /// </summary>
    class OracleDataAccess : DataAccess
    {
        /// <summary>
        /// 打開Oracle數據連接
        /// </summary>
        public override void OpenConnection(){}
        /// <summary>
        /// 關閉Oracle數據連接
        /// </summary>
        public override void CloseConnection(){}
        /// <summary>
        /// 執行Oracle數據命令
        /// </summary>
        public override void ExecuteCommand(){}
    }

 

[L] Liskov Substitution Principle(里氏替換原則)

里氏替換原則 :里氏替換原則 認為“程式中的對象應該是可以在不改變程式正確性的前提下被它的子類所替換的”的概念。

軟體工程大師Robert C. Martin把里氏替換原則最終簡化為一句話:“Subtypes must be substitutable for their base types”。也就是,子類必須能夠替換成它們的基類。即:子類應該可以替換任何基類能夠出現的地方,並且經過替換以後,代碼還能正常工作。另外,不應該 在代碼中出現if/else之類對子類類型進行判斷的條件。里氏替換原則LSP是使代碼符合開閉原則的一個重要保證。正是由於子類型的可替換性才使得父類 型的模塊在無需修改的情況下就可以擴展。在很多情況下,在設計初期我們類之間的關係不是很明確,LSP則給了我們一個判斷和設計類之間關係的基準:需不需 要繼承,以及怎樣設計繼承關係。
當一個子類的實例應該能夠替換任何其超類的實例時,它們之間才具有is-A關係。繼承對於OCP,就相當於多態性對於里氏替換原則。子類可以代替基類,客戶使用基類,他們不需要知道派生類所做的事情。這是一個針對行為職責可替代的原則,如果S是T的子類型,那麼S對象就應該在不改變任何抽象屬性情況下替換所有T對象。

                                                   

    class Rectangle
    {
        protected int width = 0;
        protected int height = 0;
        public virtual void SetWidth(int width)
        {
            this.width = width;
        }
        public virtual void SetHeight(int height)
        {
            this.height = height;
        }
        public virtual int GetArea()
        {
            return this.width * this.height;
        }
    }
    class Square : Rectangle
    {
        public override void SetHeight(int height)
        {
            this.height = height;
            this.width = height;
        }
        public override void SetWidth(int width)
        {
            this.height = width;
            this.width = width;
        }
    }

 

[I] Interface Segregation Principle(介面隔離原則)

介面隔離原則 :介面隔離原則 認為“多個特定客戶端介面要好於一個寬泛用途的介面”的概念。 

不能強迫用戶去依賴那些他們不使用的介面。換句話說,使用多個專門的介面比使用單一的總介面總要好。註意:在代碼中應用ISP並不一定意味著服務就是絕對安全的。仍然需要採用良好的編碼實踐,以確保正確的驗證與授權。
這個原則起源於施樂公司,他們需要建立了一個新的印表機系統,可以執行諸如裝訂的印刷品一套,傳真多種任務。此系統軟體創建從底層開始編製,並實現了這些 任務功能,但是不斷增長的軟體功能卻使軟體本身越來越難適應變化和維護。每一次改變,即使是最小的變化,有人可能需要近一個小時的重新編譯和重新部署。這 是幾乎不可能再繼續發展,所以他們聘請羅伯特Robert幫助他們。他們首先設計了一個主要類Job,幾乎能夠用於實現所有任務功能。只要調用Job類的 一個方法就可以實現一個功能,Job類就變動非常大,是一個胖模型啊,對於客戶端如果只需要一個列印功能,但是其他無關列印的方法功能也和其耦合,ISP 原則建議在客戶端和Job類之間增加一個介面層,對於不同功能有不同介面,比如列印功能就是Print介面,然後將大的Job類切分為繼承不同介面的子 類,這樣有一個Print Job類,等等。

                                                   

    interface IDataAccess
    {
        void OpenConnection();
        void CloseConnection();
    }

    interface ISqlDataAccess : IDataAccess
    {
        void ExecuteSqlCommand();
    }
    interface IOracleDataAccess : IDataAccess
    {
        void ExecuteOracleCommand();
    }
    class SqlDataAccess : ISqlDataAccess
    {
        /// <summary>
        /// 執行Sql數據命令
        /// </summary>
        public void ExecuteSqlCommand(){}

        /// <summary>
        /// 打開Sql數據連接
        /// </summary>
        public void OpenConnection(){}

        /// <summary>
        /// 關閉Sql數據連接
        /// </summary>
        public void CloseConnection(){}
    }
    class OracleDataAccess : IOracleDataAccess
    {
        /// <summary>
        /// 執行Oracle數據命令
        /// </summary>
        public void ExecuteOracleCommand(){}

        /// <summary>
        /// 打開Oracle數據連接
        /// </summary>
        public void OpenConnection(){}

        /// <summary>
        /// 關閉Oracle數據連接
        /// </summary>
        public void CloseConnection(){}
    }

 

[D] Dependency Inversion Principle(依賴反轉原則)

依賴反轉原則: 依賴反轉原則 認為一個方法應該遵從“依賴於抽象而不是一個實例” 的概念。依賴註入是該原則的一種實現方式。

依賴倒置原則(Dependency Inversion Principle,DIP)規定:代碼應當取決於抽象概念,而不是具體實現。
高層模塊不應該依賴於低層模塊,二者都應該依賴於抽象 
抽象不應該依賴於細節,細節應該依賴於抽象 
類可能依賴於其他類來執行其工作。但是,它們不應當依賴於該類的特定具體實現,而應當是它的抽象。這個原則實在是太重要了,社會的分工化,標準化都 是這個設計原則的體現。顯然,這一概念會大大提高系統的靈活性。如果類只關心它們用於支持特定契約而不是特定類型的組件,就可以快速而輕鬆地修改這些低級 服務的功能,同時最大限度地降低對系統其餘部分的影響。

                                                  

 

    interface IBankAccount
    {
        long BankNumber { get; set; } // 卡號
        decimal Balance { get; set; } // 餘額
    }
// 轉賬人 interface ITransferSource : IBankAccount { void CutPayment(decimal value); }
// 收款人 interface ITransferDestination : IBankAccount { void AddMoney(decimal value); }
class BankAccout : IBankAccount, ITransferSource, ITransferDestination { public long BankNumber { get; set; } public decimal Balance { get; set; } public void CutPayment(decimal value) { Balance -= value; } public void AddMoney(decimal value) { Balance += value; } }
class TransferAmount { public decimal Amount { get; set; } public void Transfer(ITransferSource source, ITransferDestination dest) { source.CutPayment(Amount); dest.AddMoney(Amount); } }

參考於:

http://www.cnblogs.com/Ax0ne/p/3619481.html

http://www.cnblogs.com/shanyou/archive/2009/09/21/1570716.html


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

-Advertisement-
Play Games
更多相關文章
  • 流程式控制制 --道心 輸入用戶名,進行判斷 name=input("請輸入用戶名:") #值對比,記憶體地址對比(值相同,記憶體不必相同) if name =="daoxin": print("登陸成功") else: print("登陸失敗") 輸入用戶名和密碼進行判斷: import getpass ...
  • 信號與槽可以通過使用手寫代碼顯式的實現關聯 ,也可以運用 QMetaObject 類規定的槽 函數命名範式來實現自動關聯。 我們只需按照下麵的標準格式定 義槽函數,這之後,uic 將會根據 QMetaObject 類制定的規則,生成界面實體類的 setupUi() 函數的內容,並完成信號與槽的關聯... ...
  • 我們都知道,申請的資源,使用完畢後要釋放。但是這個釋放動作,一定要註意。 舉個例子,很多人動態分配的資源,在使用之後,往往直接調用了delete,而不管申請資源的時候用的是new還是new[]。 如下: #include using namespace std; int main(){ int *p... ...
  • XML.01-語法簡介 文檔聲明 元素(標簽) 屬性 註釋 特殊字元 CDATA區域 處理指令 啥是XML? xml (Extensible Markup Language)可擴展的標記語言,顧名思義,XML最重要的兩個因素: 可擴展 標簽,可以自定義的標簽 XML可以看作是HTML的一個超集,但是 ...
  • 本人起初是用Eclipse+Pydev學習python的,其實也覺得挺好用。不過後來因為同事推薦去試了下PyCharm,就一發不可收拾的愛上了。 嚴格來說,題目上的問題其實對於很多人都不算是問題,但是根據個人經驗,恐怕和我一樣野生自學的孩子們還真的有可能不知道,所以特別提一下。 問題現象: 在PyC ...
  • 使用Java應用程式發送E-mail十分簡單,但是首先你應該在你的機器上安裝JavaMail API 和Java Activation Framework (JAF) 。你可以在 JavaMail (Version 1.2) 下載最新的版本。你可以再 在JAF (Version 1.1.1)下載最新... ...
  • 閱讀目錄 前言 場景1的思考 場景2的思考 避坑方式 實踐 結語 一、前言 在上一篇中(如何一步一步用DDD設計一個電商網站(八)—— 會員價的集成),有一行註釋的代碼: 其中涉及的到問題是關於值對象的持久化問題。是的,由於我們之前的設計中持久化是僅針對聚合根的: 但是有時候難免會遇到一些需要持久化 ...
  • 最近線上碰到一點小問題,分析其原因發現是出在對 RPC 使用上的一些細節掌握不夠清晰導致。很多時候我們做業務開發會把 RPC 當作黑盒機制來使用,但若不對黑盒的工作原理有個基本掌握,也容易犯一些誤用的微妙錯誤。 雖然曾經已經寫過一篇 "《RPC 的概念模型與實現解析》" 從概念模型和實現細節上講述了 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...