寫代碼的第一性原理-設計原則

第一性原理是被馬斯克帶火的。現在很多課裏都在講第一性原理,這裏簡單給第一性原理下個定義:透事物的本質,要把事物分解成最基本的組成,從源頭解決問題

那麼寫代碼的第一性原理是什麼呢?我覺得是前輩們總結設計原則,下面是常用的設計原則。

設計原則

SOLID 原則

1. SRP 單一職責原則

一個類只負責完成一個職責或者功能。單一職責原則通過避免設計大而全的類,避免將不相關的功能耦合在一起,來提高類的內聚性。同時,類職責單一,類依賴的和被依賴的其他類也會變少,減少了代碼的耦合性,以此來實現代碼的高內聚、松耦合。但是,如果拆分得過細,實際上會適得其反,反倒會降低內聚性,也會影響代碼的可維護性。不同的應用場景、不同階段的需求背景、不同的業務層面,對同一個類的職責是否單一,可能會有不同的判定結果。實際上,一些側面的判斷指標更具有指導意義和可執行性,比如,出現下面這些情況就有可能說明這類的設計不滿足單一職責原則:

  • 類中的代碼行數、函數或者屬性過多;

  • 類依賴的其他類過多或者依賴類的其他類過多;

  • 私有方法過多;比較難給類起一個合適的名字;

  • 類中大量的方法都是集中操作類中的某幾個屬性。

2.OCP 開閉原則

​ 添加一個新的功能,應該是通過在已有代碼基礎上擴展代碼(新增模塊、類、方法、屬性等),而非修改已有代碼(修改模塊、類、方法、屬性等)的方式來完成。關於定義,我們有兩點要注意。第一點是,開閉原則並不是說完全杜絕修改,而是以最小的修改代碼的代價來完成新功能的開發。第二點是,同樣的代碼改動,在粗代碼粒度下,可能被認定爲“修改”;在細代碼粒度下,可能又被認定爲“擴展”。

如何做到“對擴展開放、修改關閉”?

​ 我們要時刻具備擴展意識、抽象意識、封裝意識。在寫代碼的時候,我們要多花點時間思考一下,這段代碼未來可能有哪些需求變更,如何設計代碼結構,事先留好擴展點,以便在未來需求變更的時候,在不改動代碼整體結構、做到最小代碼改動的情況下,將新的代碼靈活地插入到擴展點上。很多設計原則、設計思想、設計模式,都是以提高代碼的擴展性爲最終目的的。特別是 23 種經典設計模式,大部分都是爲了解決代碼的擴展性問題而總結出來的,都是以開閉原則爲指導原則的。最常用來提高代碼擴展性的方法有:多態、依賴注入、基於接口而非實現編程,以及大部分的設計模式(比如,裝飾、策略、模板、職責鏈、狀態)。

3.LSP 裏式替換原則

​ 子類對象能夠替換程序中父類對象出現的任何地方,並且保證原來程序的邏輯行爲不變及正確性不被破壞。

裏式替換原則是用來指導繼承關係中子類該如何設計的一個原則。理解裏式替換原則,最核心的就是理解“design by contract,按照協議來設計”。父類定義了函數的“約定”,那子類可以改變函數的內部實現邏輯,但不能改變函數的原有“約定”。這裏的“約定”包括:函數聲明要實現的功能;對輸入、輸出、異常的約定;甚至包括註釋中所羅列的任何特殊說明。

​ 理解這個原則,我們還要弄明白,裏式替換原則跟多態的區別。雖然從定義描述和代碼實現上來看,多態和裏式替換有點類似,但它們關注的角度是不一樣的。多態是面向對象編程的一大特性,也是面向對象編程語言的一種語法。它是一種代碼實現的思路。而裏式替換是一種設計原則,用來指導繼承關係中子類該如何設計,子類的設計要保證在替換父類的時候,不改變原有程序的邏輯及不破壞原有程序的正確性

4.ISP 接口隔離原則

​ 客戶端不應該強迫依賴它不需要的接口。其中的“客戶端”,可以理解爲接口的調用者或者使用者。理解“接口隔離原則”的重點是理解其中的“接口”二字。這裏有三種不同的理解。

​1)如果把“接口”理解爲一組接口集合,可以是某個微服務的接口,也可以是某個類庫的接口等。如果部分接口只被部分調用者使用,我們就需要將這部分接口隔離出來,單獨給這部分調用者使用,而不強迫其他調用者也依賴這部分不會被用到的接口。

​2) 如果把“接口”理解爲單個 API 接口或函數,部分調用者只需要函數中的部分功能,那我們就需要把函數拆分成粒度更細的多個函數,讓調用者只依賴它需要的那個細粒度函數。

  1. 如果把“接口”理解爲 OOP 中的接口,也可以理解爲面向對象編程語言中的接口語法。那接口的設計要儘量單一,不要讓接口的實現類和調用者,依賴不需要的接口函數。

單一職責原則針對的是模塊、類、接口的設計。接口隔離原則相對於單一職責原則,一方面更側重於接口的設計,另一方面它的思考的角度也是不同的。接口隔離原則提供了一種判斷接口的職責是否單一的標準:通過調用者如何使用接口來間接地判定。如果調用者只使用部分接口或接口的部分功能,那接口的設計就不夠職責單一。

5.DIP 依賴倒置原則

1)控制反轉:

​ 控制反轉是一個比較籠統的設計思想,並不是一種具體的實現方法,一般用來指導框架層面的設計。這裏所說的“控制”指的是對程序執行流程的控制,而“反轉”指的是在沒有使用框架之前,程序員自己控制整個程序的執行。在使用框架之後,整個程序的執行流程通過框架來控制。流程的控制權從程序員“反轉”給了框架。

2)依賴注入

依賴注入和控制反轉恰恰相反,它是一種具體的編碼技巧。不用直接 new 的方式在類內部創建依賴類的對象,而是將依賴的類對象在外部創建好之後,通過構造函數、函數參數等方式傳遞給類來使用。

KISS原則

​ KISS 原則的中文描述是:儘量保持簡單。KISS 原則是保持代碼可讀和可維護的重要手段。KISS 原則中的“簡單“”並不是以代碼行數來考量的。代碼行數越少並不代表代碼越簡單,我們還要考慮邏輯複雜度、實現難度、代碼的可讀性等。而且,本身就複雜的問題,用複雜的方法解決,也並不違背 KISS 原則。除此之外,同樣的代碼,在某個業務場景下滿足 KISS 原則,換一個應用場景可能就不滿足了。

YAGNI 原則

YAGNI 原則的英文全稱是:You Ain’t Gonna Need It。直譯就是:你不會需要它。當用在軟件開發中的時候,它的意思是:不要去設計當前用不到的功能;不要去編寫當前用不到的代碼。實際上,這條原則的核心思想就是:不要做過度設計。YAGNI 原則跟 KISS 原則並非一回事兒。KISS 原則講的是“如何做”的問題(儘量保持簡單),而 YAGNI 原則說的是“要不要做”的問題(當前不需要的就不要做)。

DRY 原則

DRY 原則中文描述是:不要重複自己,將它應用在編程中,可以理解爲:不要寫重複的代碼。

重複可以包括實現邏輯重複、功能語義重複、代碼執行重複。

​ 實現邏輯重複,但功能語義不重複的代碼,並不違反 DRY 原則。實現邏輯不重複,但功能語義重複的代碼,也算是違反 DRY 原則。而代碼執行重複也算是違反 DRY 原則

迪米特法則

​ 不該有直接依賴關係的類之間,不要有依賴;有依賴關係的類之間,儘量只依賴必要的接口。迪米特法則是希望減少類之間的耦合,讓類越獨立越好。每個類都應該少了解系統的其他部分。一旦發生變化,需要了解這一變化的類就會比較少

迪米特法則體現了“高內聚、松耦合”,“高內聚”用來指導類本身的設計,“松耦合”用來指導類與類之間依賴關係的設計。所謂高內聚,就是指相近的功能應該放到同一個類中,不相近的功能不要放到同一類中。所謂“松耦合”指的是在代碼中類與類之間的依賴關係簡單清晰。

學習資料:極客時間《設計模式之美》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章