主頁 > 軟體設計 > 經典設計原則 - SOLID

經典設計原則 - SOLID

2022-08-19 08:32:11 軟體設計

SOLID 設計原則包含以下 5 種原則:

  • 單一職責原則(Single Responsibility Principle, SRP)
  • 開閉原則(Open Closed Principle, OCP)
  • 里式替換原則(Liskov Substitution Principle, LSP)
  • 介面隔離原則(Interface Segregation Principle, ISP)
  • 依賴反轉原則(Dependency Inversion Principle, DIP)

單一職責原則

理解

單一職責原則的描述是,一個類或者模塊只負責完成一個職責(或功能),當然,單一職責原則不止是可以針對于模塊或類,對于很多粒度都有效果,如函式、類、介面、模塊等等,模塊通常由多個類組成,

職責可以指模塊變化的原因,從這個角度理解,單一職責原則表示不要存在超過一個導致模塊變更的原因,

需要注意的是,不同的應用場景、不同階段的需求背景、不同的業務層面,對同一個類的職責是否單一,可能會有不同的判定結果,

優點

遵循單一職責原則,將會有以下的優點:

  • 提高代碼的可維護性:職責越少,復雜度越低,可讀性更好,可維護性就更高
  • 降低代碼變更的風險:職責越多,代碼變更的可能性就越高,變更帶來的風險也就越大

最佳實踐

在實際開發中,出現以下現象有可能違反了單一職責原則:

  • 模塊的變數、屬性或代碼行數過多
  • 模塊的內部對外部依賴過多
  • 模塊的私有方法過多
  • 難以給模塊取一個合理的名稱
  • 模塊的大部分操作只針對幾個屬性

如出現上述情況,則需要判斷是否對代碼做職責分離,以遵循單一職責原則,最終應以提高內聚、降低耦合、保證代碼的可維護性為主,

開閉原則

理解

開閉原則的描述是,軟體物體(模塊、類、方法等)應該“對擴展開放、對修改關閉”,

詳細的解釋就是,添加一個新的功能時,在已有代碼基礎上擴展代碼(新增模塊、類、方法等),而非修改已有代碼(修改模塊、類、方法等),更寬松的理解是以最小的修改代碼的代價來完成新功能的開發,

優點

遵循開閉原則,將會有以下的優點:

  • 減少測驗范圍:修改的代碼范圍越小,涉及的測驗范圍越小,未改動的測驗代碼仍能正常運行
  • 降低維護成本:軟體規模越大、壽命越長,則軟體的維護成本越高

最佳實踐

若要做到“對擴展開發、對修改關閉”,有以下幾點需要注意:

  • 時刻具備擴展意識、抽象意識、封裝意識,多花時間設計代碼結構,事先留好擴展點
  • 大部分經典設計模式都是為了解決代碼的擴展性問題而總結出來的,開閉原則是它們一個重要的評價依據

里式替換原則

理解

里式替換原則的描述是,子類物件能夠替換程式中父類物件出現的任何地方,并且保證原來程式的邏輯行為不變及正確性不被破壞,

從代碼實作上看,面向物件的多型和里式替換原則有點類似,但是它們的關注點不一樣:里式替換原則是用來指導繼承關系中子類該如何設計,子類的設計要保證在替換父類的時候,不改變原有程式的邏輯以及不破壞原有程式的正確性,

優點

遵循里式替換原則,將會有以下的優點:

  • 實作有意義的繼承:保證了父類的復用性,也降低了系統出錯誤的故障,防止誤操作,同時也不會破壞繼承的機制
  • 增強程式的健壯性:不同的子類可以完成不同的業務邏輯,即使增加子類也能保持非常好的兼容性

最佳實踐

通常,需要注意以下違反里式替換原則的代碼:

  • 子類違背父類宣告要實作的功能,如將加法改成減法
  • 子類違背父類對輸入、輸出、例外的約定,如同一情況拋出的例外不同等
  • 子類違背父類注釋中所羅列的任何特殊宣告

介面隔離原則

理解

介面隔離原則的描述是,介面的呼叫者或使用者不應該被強迫依賴它不需要的介面,

通過對介面的理解不同,介面隔離原則有以下三種理解:

1、如果把“介面”理解成一組介面集合,可以是某個微服務的介面,也可以是某個類別庫的介面等,如果存在部分介面只被部分呼叫者使用,就需要將這部分介面隔離出來,單獨給這部分呼叫者使用,而不強迫其他呼叫者也依賴其他不會用到的介面,

2、如果把“介面”理解成單個 API 介面或函式,部分呼叫者只需要其中的部分功能,則需要將這個函式拆分成更細粒度的多個函式,讓呼叫者只依賴它需要的那個細粒度函式,

3、如果把“介面”理解成 OOP 中的介面,也可以理解成為面向物件編程語言中的介面語法,那介面的設計要盡量單一,不要讓介面的實作類和呼叫者依賴不需要的介面函式,

介面隔離原則和單一職責原則有點類似,但介面隔離原則更側重于介面的設計,通常是通過呼叫者如何使用介面來定義這個介面的設計是否足夠職責單一,

優點

遵循介面隔離原則,將會有以下的優點:

  • 高內聚,低耦合:拆分成更小粒度的介面,減少對外的互動,預防外來的變更,提高系統的靈活性和可維護性
  • 可讀性高,易于維護:合理的介面拆分粒度能保證系統的穩定性,減少專案工程的代碼冗余

最佳實踐

采用介面隔離原則對介面進行約束時,要注意以下幾點:

  • 介面盡量小,但是要有限度,定義過小,則會造成介面數量過多,使設計復雜化;定義多大,靈活性降低
  • 每個專案和產品都有選定的環境因素,環境不同,介面拆分的標準就不同,深入了解業務邏輯

依賴反轉原則

理解

依賴反轉原則也被叫作依賴倒置原則,其含義是:高層模塊不要依賴底層模塊,高層模塊和底層模塊應該通過抽象來互相依賴;抽象不要依賴具體實作細節,具體實作細節依賴抽象,

Tomcat 是運行 Java Web 應用程式的容器,撰寫的 Web 應用程式代碼只需要部署在 Tomcat 容器中下,便可被 Tomcat 容器呼叫執行,在這里,Tomcat 容器就是高層模塊,Web 應用程式就是底層模塊,Tomcat 容器和 Web 應用程式沒有直接的依賴關系,而是通過 Servlet 規范實作互相依賴,而 Servlet 規范也不會依賴具體的實作細節,而是 Tomcat 和 Web 應用程式依賴 Servlet 規范,

控制反轉

控制反轉(Inversion Of Control, IoC)指的是將程式員自己對程式執行流程的控制反轉成通過框架控制,控制反轉并不是一種具體的設計技巧,而是一種籠統的設計思想,一般用來指導框架層面的設計,

實作控制反轉主要有兩種方式:依賴注入和依賴查找,兩者的區別在于,前者是被動的接收物件,在類 A 的實體創建程序中即創建了依賴的 B 物件,通過型別或名稱來判斷將不同的物件注入到不同的屬性中,而后者是主動索取相應型別的物件,獲得依賴物件的時間也可以在代碼中自由控制,

依賴注入

依賴注入(Dependency Injection, DI)是一種具體的編碼技巧,

其詳細概括就是:不通過 new 的方式在類的內部創建依賴物件,而是將依賴的類物件在外部創建好之后,通過建構式、函式引數等方式傳遞(或注入)給類使用,

一個簡單的依賴注入代碼例子如下:

package cn.fatedeity.designpattern.philosophy;

/**
 * 依賴注入案例
 */
public class DependencyInjectionCase {
    private MessageSender messageSender;

    public DependencyInjectionCase(MessageSender messageSender) {
        this.messageSender = messageSender;
    }

    public void sendMessage(String phone, String message) {
        this.messageSender.send(phone, message);
    }

    public static void main(String[] args) {
        MessageSender smsSender = new SmsSender();
        DependencyInjectionCase dependencyInjectionCase0 = new DependencyInjectionCase(smsSender);
        // SmsSender sms send sms message
        dependencyInjectionCase0.sendMessage("sms", "sms message");

        MessageSender inboxSender = new InboxSender();
        DependencyInjectionCase dependencyInjectionCase1 = new DependencyInjectionCase(smsSender);
        // SmsSender inbox send inbox message
        dependencyInjectionCase1.sendMessage("inbox", "inbox message");
    }
}

class InboxSender implements MessageSender {
    @Override
    public void send(String phone, String message) {
        System.out.println("InboxSender " + phone + " send "+ message);
    }
}

class SmsSender implements MessageSender {
    @Override
    public void send(String phone, String message) {
        System.out.println("SmsSender " + phone + " send "+ message);
    }
}

interface MessageSender {
    void send(String phone, String message);
}

優點

遵循依賴反轉原則,將會有以下的優點:

  • 查詢依賴和應用代碼分離,大量降低工廠類和單例類的數量,代碼層次更加清晰
  • 沒有侵入性,無須依賴容器的 API,也無須實作一些特殊介面

最佳實踐

通過依賴注入提供的擴展點,簡單配置一下所有需要的類及其類之間依賴關系,就可以實作由框架來自動創建物件、管理物件的生命周期、依賴注入等功能,

現成的依賴注入創建有很多,比如 Google Guide、Java Spring、Pico Container、Butterfly Container 等,

首發于翔仔的個人博客,點擊查看更多,

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/502265.html

標籤:其他

上一篇:HSF轉dubbo

下一篇:部署前后端為獨立的 Docker 節點

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more