java面向對象的設計原則


一、針對java類的6大設計原則

1.單一職責原則(Single Responsibility Principle,SRP)

即:對一個類而言,有且僅有一個引起它變化的原因。否則的話就應該把這個類進行拆分。在設計時讓一個類只負責一種類型的責任。
單一職責原則的核心就是控制類的粒度大小、將對象解耦、提高內聚性。如果遵循單一職責原則將有以下優點:

  • 降低類的復雜度。一個類只負責一項職責,其邏輯肯定要比負責多項職責簡單得多。
  • 提高類的可讀性。復雜性降低,其可讀性自然會提高。
  • 提高系統的可維護性。可讀性提高了,那自然更容易維護了。
  • 變更引起的風險降低。變更是必然的,如果單一職責原則遵守的好,當修改一個功能時,可以顯著降低對其他功能的影響。

2.開放-封閉原則(Open & Closed Principle,OCP)

軟件實體(類、模塊、函數等)應該是可以擴展的,即開放的;但是是不可修改的,即封閉的。也就是當應用的需求改變時,在不修改軟件實體的源代碼或者二進制代碼的前提下,可以擴展該模塊的功能,使其滿足新的需求。
開閉原則是面向對象程序設計的終極目標,它使軟件實體擁有一定的適應性和靈活性的同時具備穩定性和延續性。
具體來說,其作用如下:

  • 對軟件測試的影響:軟件遵守開閉原則的話,軟件測試時只需要對擴展的代碼進行測試就可以了,因為原有的測試代碼仍然能夠正常運行。
  • 可以提高代碼的可復用性:粒度越小,被復用的可能性就越大;在面向對象的程序設計中,根據原子和抽象編程可以提高代碼的可復用性。
  • 可以提高軟件的可維護性:遵守開閉原則的軟件,其穩定性高和延續性強,從而易於擴展和維護。

3.里氏替換原則(Liskov Substitution Principle,LSP)

子類型必須能夠替換掉他們的基類型。即,在任何父類可以出現的地方,都可以用子類的實例來賦值給父類型的引用。當一個子類的實例應該能夠替換任何其超類的實例時,它們之間才具有是一個(is-a)關系。
例如:車是超類,轎車是子類,那么可以將轎車的實例賦值給車的實例,即 車 che=轎車();即滿足is-a的關系,即轎車是一個車,轎車是車。車的性質,轎車都具備。
繼承必須確保超類所擁有的性質在子類中仍然成立。
里氏替換原則主要闡述了有關繼承的一些原則,也就是什么時候應該使用繼承,什么時候不應該使用繼承,以及其中蘊含的原理。里氏替換原則是繼承復用的基礎,它反映了基類與子類之間的關系,是對開閉原則的補充,是對實現抽象化的具體步驟的規范。
里氏替換原則通俗來講就是:子類可以擴展父類的功能,但不能改變父類原有的功能。也就是說:子類繼承父類時,除添加新的方法完成新增功能外,盡量不要重寫父類的方法。如果通過重寫父類的方法來完成新的功能,這樣寫起來雖然簡單,但是整個繼承體系的可復用性會比較差,特別是運用多態比較頻繁時,程序運行出錯的概率會非常大。如果程序違背了里氏替換原則,則繼承類的對象在基類出現的地方會出現運行錯誤。這時其修正方法是:取消原來的繼承關系,重新設計它們之間的關系。

4.依賴倒置原則(Dependence Inversion Principle,DIP)

抽象不應該依賴於細節,而細節應該依賴於抽象。即高層模塊不應該依賴於底層模塊,二者都應該依賴於抽象。其核心思想是:要面向接口編程,不要面向實現編程。
依賴倒置原則是實現開閉原則的重要途徑之一,它降低了客戶與實現模塊之間的耦合。
其作用如下:

  • 依賴倒置原則可以降低類間的耦合性。
  • 依賴倒置原則可以提高系統的穩定性。
  • 依賴倒置原則可以減少並行開發引起的風險。
  • 依賴倒置原則可以提高代碼的可讀性和可維護性。
    依賴倒置原則的目的是通過面向接口編程來降低類間的耦合性,所以我們在實際編程中只要遵循以下4點,就能在項目中滿足這個規則:
  • 每個類盡量提供接口或抽象類,或者兩者都具備。
  • 變量的聲明類型盡量是接口或者是抽象類。
  • 任何類都不應該從具體類派生。
  • 使用繼承時盡量遵循里氏替換原則。

5.接口分離原則(Interface Segregation Principle,ISP)

不應該強迫客戶依賴於他們不用的方法。接口屬於客戶,不屬於它所在的類層次結構。即:依賴於抽象而不依賴於具體,同時在抽象級別不應該有對於細節的依賴。
接口隔離原則說的是客戶端不應該被迫依賴於它不使用的方法。接口中只能存在消費者需要使用到的方法,不應該存在消費者用不到的方法。簡單來說就是更小和更具體的瘦接口比龐大臃腫的胖接口好。其實是消費者需要接口,實現類只是提供服務,因此應該由消費者(客戶端)來定義接口。
接口隔離原則是為了約束接口、降低類對接口的依賴性,遵循接口隔離原則有以下5個優點:

  • 將臃腫龐大的接口分解為多個粒度小的接口,可以預防外來變更的擴散,提高系統的靈活性和可維護性。
  • 接口隔離提高了系統的內聚性,減少了對外交互,降低了系統的耦合性。
  • 如果接口的粒度大小定義合理,能夠保證系統的穩定性;但是,如果定義過小,則會造成接口數量過多,使設計復雜化;如果定義太大,靈活性降低,無法提供定制服務,給整體項目帶來無法預料的風險。
  • 使用多個專門的接口還能夠體現對象的層次,因為可以通過接口的繼承,實現對總接口的定義。
  • 能減少項目工程中的代碼冗余。過大的接口里面通常放置許多不用的方法,當實現這個接口的時候,被迫設計冗余的代碼。
    在具體應用接口隔離原則時,應該根據以下幾個規則來衡量:
  • 接口盡量小,但是要有限度。一個接口只服務於一個子模塊或業務邏輯。
  • 為依賴接口的類定制服務。只提供調用者需要的方法,屏蔽不需要的方法。
  • 了解環境,拒絕盲從。每個項目或產品都有選定的環境因素,環境不同,接口拆分的標准就不同,需要深入了解業務邏輯。
  • 提高內聚,減少對外交互。使接口用最少的方法去完成最多的事情。

6.最少知識原則(Least Knowledge Principle - LKP)

最少知識原則又叫迪米特法則。核心思想是:低耦合、高內聚
一個實體應當盡量少的與其他實體之間發生相互作用,使得系統功能模塊相對獨立。這樣,當一個模塊修改時,就會盡量少的影響其他的模塊,擴展會相對容易,這是對軟件實體之間通信的限制,它要求限制軟件實體之間通信的寬度和深度。

總結

總的來說,單獨應用SOLID的某一個原則並不能讓收益最大化。應該把它作為一個整體來理解和應用,從而更好地指導你的軟件設計。單一職責是所有設計原則的基礎,開閉原則是設計的終極目標。里氏替換原則強調的是子類替換父類后程序運行時的正確性,它用來幫助實現開閉原則。而接口隔離原則用來幫助實現里氏替換原則,同時它也體現了單一職責。依賴倒置原則是過程式編程與OO編程的分水嶺,同時它也被用來指導接口隔離原則。如下圖所示:


二、針對包設計的6大原則

在軟件開發中有包的概念,而包可以理解為存放一些相關類的容器。通過把類組織成包,我們可以在更高層次的抽象上理解設計。我們也可以通過包來管理軟件的開發和發布。一個包中的類會和其他包的類存在依賴,跨越包的邊界,因此包之間也會產生依賴關系。

1.重用發布等價原則( Release Reuse Equivalency Principle,REP)

重用的粒度就是發布的粒度。屬於包設計的范疇。包是相關的類的集合,換言之一個類基本上都和其他的一些有依賴關系。因此發布的最小單位一般認為是一個包。那么問題來了,包里面包含的所有類都是可以重用的嗎?不是的,可以重用的包中不能包含不可重用的類。因為不可重用的類參照了其他組件,包含這個類的這個包就變成不能重用了。而一個包的內容應該是為了同一個重用的目的編寫的,也就是說一個包中的內容都是同一種類型,為了同一種類型的功能而編寫的。

2.共同封閉原則(Common Closure Principle,CCP)

包中的所有類對於同一類性質的變化應該是共同封閉。一個變化若對一個包產生影響,則將對該包中的所有類產生影響,而對於其他的包不造成影響。也就是說一起修改的類,應該組合在一起(同一個包里)。
如果必須修改應用程序里的代碼,我們希望所有的修改都發生在一個包里(修改關閉),而不是遍布在很多包里。
CCP原則就是把因為某個同樣的原因而需要修改的所有類組合進一個包里。如果2個類從物理上或者從概念上聯系得非常緊密,它們通常一起發生改變,那么它們應該屬於同一個包。
CCP跟開閉原則(OCP: Open Closed Principle) 有着很深的淵源關系,CCP的“關閉”(closure)就是OCP所提倡的:classes should be closed for modification but open for extension. 類應該對修改關閉,對擴展開放。但我們知道,100%的“關閉”是不現實的,我們在設計系統時,只能盡量地保持對大多數可預見的修改關閉。
CCP延伸了OCP的“關閉”概念,當因為某個原因需要修改時,把需要修改的范圍限制在一個最小范圍內的包里。
CCP原則幫助我們決定哪些類應該被放到同一個包里。

3.共同重用原則(Common Reuse Principle,CRP )

一個包中的所有類應該是共同重用的。如果重用了包中的一個類,那么就要重用包中的所有類。
包經常以JAR、DLL的形式出現。如果被使用的包以JAR包的形式發布,那么使用這個包的代碼即使只依賴這個包的一個類,也將依賴這個包。所以如果JAR包的內容進行了修改,即使是對非依賴的類進行了修改,也會影響使用者重新驗證和發布新的版本。因此我們希望,一個包中的類都是不可分開的,僅僅只依賴其中的一部分情況應盡可能不出現。

4.無環依賴原則(Acyclic Dependencies Principle,ADP)

在包的依賴關系圖中不允許存在環,即包之間的結構必須是一個直接的無環圖形。

5.穩定依賴原則(Stable Dependencies Principle,SDP )

朝着穩定的方向進行依賴。

6.穩定抽象原則(Stable Abstractions Principle,SDP)

包的抽象程度應該和其穩定程度一致。一個穩定的包應該是抽象的,這樣它的穩定性就不會使其無法擴展。另外,一個不穩定的包應該是具體的,因為它的不穩定性使其內部的具體代碼易於修改。

三、其他設計原則

1.DRY( Don't repeat yourself,即避免重復代碼)

避免重復代碼原則提出,每一段代碼都必須在系統中有唯一的明確的目的。

2.KISS(Keep It Simple, Stupid ,即簡單就是美)

不要讓系統變得復雜,界面簡潔,功能實用,操作方便,要讓它足夠的簡單,足夠的傻瓜。KISS原則傳達的是:讓事情變得更簡單而不是復雜。

3.高內聚與低耦合(High Cohesion and Low Coupling - HCLC)

模塊內部需要做到內聚度高,模塊之間需要做到耦合度低。

4.慣例優於配置(Convention over Configuration - COC)

盡量讓慣例來減少配置,這樣才能提高開發效率,盡量做到“零配置”。即所謂約定優於配置。

5.關注點分離(Separation of Concerns - SOC)

將一個復雜的問題分離為多個簡單的問題,然后逐個解決這些簡單的問題,那么這個復雜的問題就解決了。

6.YAGNI(You Ain't Gonna Need It,即我們不應該為程序編寫尚未用到的功能)

YANGI原則建議如果你找不到一個某段代碼存在的理由,就必須對其進行重構或剔除。只留有用的代碼和注釋,沒用的變量,方法,import類都要及時去掉,以保持代碼簡潔。

7.用更少的代碼做更多的事。less is more.


參考博文:
(1) https://www.cnblogs.com/shamao/p/10875528.html
(2) https://www.jianshu.com/p/15edb371c0b5 (多種設計模式的講解)
(3) https://insights.thoughtworks.cn/what-is-solid-principle/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM