一.“單一職責”原則(Single Respnsibility Principle) SRP
單一職責原則的定義是:應該有且僅有一個原因引起類的變更。
單一職責原則的好處:
1、類的復雜性降低,實現什么職責都有清晰的定義;
2、可讀性提高,復雜性降低,那當然可讀性就提高了;
3、可維護性提高,可讀性提高,那當然更容易維護了;
4、變更引起的風險降低,變更是必不可少的,如果一個接口的單一職責做得好,一個接口修改只對相應的實現類有影響,對其他的接口無影響,這對系統的擴展性、維護性都有非常大的幫助。
單一職責原則適用於接口,類,也同樣適用於方法,什么意思呢?一個方法盡可能去做一件事情。比如一個方法“修改用戶密碼”,不要把這個方法放到“修改用戶信息”方法中,這個方法的顆粒很粗。
對於單一職責,給予的建議是:接口一定要做到單一職責,類的設計盡量做到只有一個原因引起變化。
注意:單一職責原則提出了一個編寫程序的標准,用“職責”或“變化原因”來衡量接口或類設計得是否優良,但是“職責”和“變化原因”都是不可度量的,因項目而異,因環境而異。
二.“里氏替換”原則(Liskvo Substitution Principle) LSP
里氏替換原則的定義是:所有引用基類的地方必須能透明地使用到其子類的對象。
里氏替換原則的好處:
1、代碼共享,減少創建類的工作量,每個子類都擁有父類的方法和屬性;
2、提高代碼的重用性;
3、子類可以形似父類,但又異於父類,“龍生龍,鳳生鳳,老鼠生來會打洞”是說子擁有父的“種”,“世界上沒有兩片完全相同的葉子”是指明子和父的不同;
4、提高代碼的可擴展性,實現父類的方法就可以“為所欲為”了,可以看到很多開源框架的擴展接口都是通過繼承父類來完成的;
5、提高產品或項目的開放性;
當然繼承也是有缺點的,缺點如下:
1、繼承是浸入性的。只要繼承,就必須擁有父類的所有屬性和方法;
2、降低代碼的靈活性。子類必須擁有父類的所有屬性和方法,讓子類自由的世界中多了些約束;
3、增強了耦合性。當父類的常量、變量和方法被修改時,必須要考慮子類的修改,而且是在缺乏規范的環境下,這種修改可能帶來非常糟糕的結果----大片代碼需要重構。
注意:如果子類不能完整地實現父類的方法,或者父類的某些方法在子類中已經發生“畸變”,則建議斷開父子繼承關系,采用依賴、聚集、組 合等關系代替繼承。里氏替換原則可以正着用,但是不能反着用,在子類出現的地方,父類未必就可以勝任。
里氏替換原則為良好的繼承定義了一個規范:
1、子類必須完全實現父類的方法;
2、子類可以有自己的個性;
3、覆蓋或實現父類的方法時輸入參數可以被放大;(子類中方法的前置條件(即傳入參數類型)必須與超類中被覆寫的方法的前置條件相同或更寬松)。
4、覆寫或實現父類的方法時輸出結果可以被縮小;
三.“依賴倒置”原則(Dependence Inversion Principle) DIP
依賴倒置原則在java語言中的表現是:
1、模塊間的依賴通過抽象發生,實現類之間不能發生直接的依賴關系,其依賴關系是通過接口或抽象類產生的;
2、接口或抽象類不依賴於實現類;
3、實現類依賴接口或抽象類;
更加精簡的定義就是“面向接口編程”------OOD的精髓之一。
依賴倒置原則的好處:
依賴倒置原則可以減少類間的耦合性,提高系統的穩定性,降低並行開發引起的風險,提高代碼的可讀性和可維護性。
要遵循依賴倒置原則,在項目開發中需要遵循的原則應該有:
1、 每一個類盡量都有接口或抽象類,或者抽象類和接口兩者都具備;
2、 變量的表面類型盡量都是接口或是抽象類;
3、任何類都不應該從具體類派生(只要不超過兩層的繼承都是可以忍受的,特別是負責項目維護的同志,基本上可以不考慮這個原則);
4、盡量不要覆寫基類的方法
5、結合里氏替換原則使用;
依賴的三種寫法:
只要做到抽象依賴,即時是多層的依賴關系也無所畏懼。
1、構造函數傳遞依賴對象;
2、Setter方法傳遞依賴對象;
3、接口聲明傳遞依賴對象;
注意:設計是否具備穩定性,只要適當地“松松土”,觀察“設計的藍圖”是否還可以茁壯地成長就可以得出結論,穩定性較高的設計,在周圍環境頻繁發生變化的時候,依然可以做到“我自巋然不動”。
四.“接口隔離”原則(Interface Isolation)II
接口隔離原則的定義:建立單一接口,不要建立臃腫龐大的接口。
通俗說:接口盡量細化,同時接口中的方法盡量。當然說到這里,有些人會認為這與單一職責不是相同的嗎?錯!接口隔離原則與單一職責原則的審視角度是不同的,單一職責原則是類和接
職責單一,注重的是職責,這是業務邏輯上的划分,而接口隔離原則要求接口的方法盡量少。例如:一個接口的職責可能包含10個方法,這10個方法都放在一個接口中,並且提供給
多個模塊訪問,各個模塊按照規定的權限來訪問,在外通過文檔約束“不使用的方法不要訪問”,按照單一職責原則是允許的,按照接口隔離原則是不允許的,因為它要求“盡量使用
多個專門的接口”。專門的接口指的是什么?就是指提供給每個模塊的都應該是單一接口,提供幾個模塊就應該有幾個接口,而不是建立一個龐大的臃腫的接口,容納所有的客戶端訪問。
接口是我們設計時對外提供的契約,通過分散定義多個接口,可以預防未來變更的擴散,提高系統的靈活性和可維護性。
保證接口的純潔性:
接口隔離原則是對接口進行規范約束,其包含以下4層含義:
1、接口要盡量小,根據接口隔離原則拆分接口時,首先必須滿足單一職責原則;
2、接口要高內聚,高內聚就是提高接口、類、模塊的處理能力,減少對外的交互,要求在接口中盡量少公布public方法,接口是對外的承諾,承諾是對外的承諾,承諾越少對系統的開發越有利,變更的
風險也就越少,同時也有利於降低成本;
3、定制服務,即單獨為一個個體提供優良的服務,要求只提供訪問者需要的方法;
4、接口的設計是有限度的;
注意:接口隔離原則是對接口的定義,同時也是對類的定義,接口和類盡量使用原子接口或原子類來組裝。
五.“迪米特”法則(Law of Demeter)LoD
迪米特法則的定義:也成最小知識原則(Least Knowledge Principle)LKP,一個對象應該對其他對象有最少的了解。
通俗說:一個類應該對自己需要耦合和調用的類知道得最少,你(被耦合或調用的類)的內部是如何復雜都和我沒關系,那是你的事情,我就知道你提供的這么多public方法,我就調用這么多,其他我一概不關心。
