《設計模式之禪》-1.六大原則
1.單一職責原則:
定義:應該有且僅有一個原因引起類的變更
好處:
1.類的複雜性降低,實現什麼職責都有清晰明確的定義;
2.可讀性提高,複雜性降低;
3.可維護性提高,可讀性提高;
4.變更引起的風險降低。變更是必不可少的,如果介面的單一職責做得好,一個介面修改只對相應的實現類有影響,對其他的介面無影響,這對系統的擴充套件性,維護性都有非常大的幫助
--------------------------------------------------------------------------------------------------------------------
2.里氏替換原則
定義:只要父類能出現的地方子類就可以出現,而且替換成子類也不會產生任何錯誤或異常
規範:
1.子類必須完全實現父類的方法
2.子類可以實現自己的方法
3.覆蓋或實現父類的方法時輸入引數可以被放大(子類擁有父類的所有屬性和方法,方法名相同,輸入引數型別又不相同,是過載)
注意:
子類中方法的前置條件必須和超類中被覆寫的方法的前置條件相同或者更加寬鬆,否則會執行子類的方法會引起邏輯混亂
----------------------------------------------------------------------------------------------------------------------------
3.迪米特法則
定義
迪米特法則也稱為最少知識原則
一個物件應該對其他物件有最少的瞭解,通俗地講,一個類應該對自己需要耦合或呼叫的類知道最少
迪米特法則對類的低耦合提出了明確的要求
1.只和朋友交流
朋友類的定義:出現在成員變數,方法的輸入輸出引數中的類稱為成員朋友類,而出現在方法體內部的類不屬於朋友類
一個類只和朋友類交流,不和陌生類交流,類和類之間的關係應該是建立類之間,而不是方法中間
例如:
A類中生產一個數組,傳入B類,B類中有一個計算陣列長度的方法countSize
class A{ void commond(B b){ List<integer> list = new Arrary(); for(int i =0;i<20;i++;){ list.add(i); } b.countSize(list); } } class B{ void countSize(List<integer> list){ sys.out.print(list.size) }
A類只有一個B類是朋友類,而list是方法內部的類不算朋友類,而迪米特法則告訴我們
只和朋友類交流,但是定義的commond方法聲明瞭一個list動態陣列,這樣會破壞A類的健壯性,因為方法是類的一個行為,而類不知道自己的行為和其他類產生了依賴關係,這是違反了迪米特原則的
class A{
void commond(B b){
b.countSize();
}
}
class B{
private List<integer> list;
B(List<integer> list){
this.list = list;
}
void countSize(List<integer> list){
sys.out.print(this.list.size)
}
}
這樣就可以避免A類對陌生類List的訪問,降低了耦合性,提高了系統的健壯性
2.朋友之間也是要有距離的
朋友類儘量不要暴露過多的public方法,因為這會導致類與類之間的耦合性變得很強,後期維護改動上會很難維護,朋友類儘量把可以封裝的邏輯封裝在自身,這也體現了類的高內聚特性,把封裝好的邏輯用一個public方法暴露出去,這樣呼叫類和朋友類的耦合關係會降低,結構也清晰
一個類公開的public屬性或方法越多,修改時涉及的面就越大,變更引起的風險擴散也越大
3.是自己的就是自己的
如果一個方法放在本類中,既不增加類間的關係,也不會對本類產生負面影響,就放置在本類中
4.謹慎的使用Serializable
客戶端修改了,而服務端沒有做出相應的修改,則會報序列化錯誤,這個問題很少出現,就算出現了也很快會解決
最佳實踐
迪米特法則的核心思想就是 類間的解耦,弱耦合,只有弱耦合了以後,類的複用率才會提高,但是會導致產生大量的中轉類和跳轉類,導致系統的複雜性提高,同時維護帶來了困難,採用迪米特法則時,需要反覆權衡
迪米特法則要求類間解耦,但是解耦是有限度的,要適度考慮這個原則
----------------------------------------------------------------------------------------------------------------------------
4.介面隔離原則
介面分為兩種
1.例項介面,在java中類也是一種介面
2.類介面,interface關鍵字所定義的介面
定義
客戶端不應該依賴它不需要的介面
類間的依賴關係應該建立在最小的介面上
將兩句話結合而言就是建立單一介面,不要建立臃腫龐大的介面,再通俗一點而言,介面應該儘量細化,同時介面中的方法應該儘量的少
與單一職責的區別
單一職責相比和介面隔離原則的審視角度不一樣
單一職責原則要求的是類和介面職責單一,注重的是職責,這是業務邏輯上的劃分,而介面隔離原則要求的是介面的方法儘量少
舉個例子:
一個介面可能職責可能包含10個方法,這10個方法都在一個介面中,並且提供給多個模組訪問,各個模組按照規定的許可權來訪問,在系統外通過文件約束“不使用的方法不要訪問”,按照單一職責原則是執行的,但是在介面隔離原則是不允許的,因為它要求“儘量使用多個專門的介面”。專門的介面是指提供給每個模組的都應該是單一介面,提供給幾個模組就幾個介面,而不是建立一個龐大的臃腫的介面,容納所有的客戶端的訪問
介面隔離原則是對介面進行規範約束
1.介面要儘量小,不出現臃腫的介面,根據介面隔離原則拆分介面時,首先必須滿足單一職責原則
2.介面要高內聚,高內聚就是提高介面,類,模組的處理能力,減少對外的互動。介面是對外的承諾,承諾越少對系統的開發越有利,變更的風險也就越小,同時有利於降低成本
3.定製服務 ,定製服務就是單獨為一個個體提供優良的服務
4.介面設計是有限度的
---------------------------------------------------------------------------------------------------------------------------
5.依賴倒置原則
1.模組間的依賴通過抽象發生,實現類之間不發生直接的依賴關係,其依賴關係是通過介面或抽象類產生的
2.介面或抽象類不依賴與實現類
3.實現類依賴介面或抽象類
注意:
在java中,只要定義變數就必然要有型別,一個變數可以有兩種型別,一個變數可以有兩種型別:表面型別和實際型別,表面型別是在定義的時候賦予的型別,實際型別是物件的型別,如zhangsan的表面型別是IDriver,實際型別是Driver
依賴的三種寫法:
建構函式傳遞依賴物件
setter方法傳遞依賴物件
介面宣告依賴物件
1.每個類儘量都有介面或抽象類,或者抽象類和介面兩者都具備
2.變數的表面型別儘量是介面或者是抽象類
3.任何類都不應該從具體類派生
4.儘量不要覆寫基類的方法
4.結合里氏替換原則使用
6.開閉原則
核心:
對擴充套件開放,對修改關閉
開閉原則告訴我們應儘量通過擴充套件軟體實體的行為來實現變化,而不是通過修改已有程式碼來完成變化,面向介面程式設計,擴充套件時,可以通過繼承介面來實現功能的增加
------------------------------------------------------------------------------------------------------------------------
※繼承的好處與缺點
好處:
1.程式碼共享,減少建立類的工作量,每個子類都擁有父類的方法和屬性
2.提高程式碼的重用性
3.子類可以形似父類,但又異於父類
4.提高程式碼的可擴充套件性
5.提高專案或產品的開放性
缺點
1.繼承是侵入性的,只要繼承就必須擁有父類的所有屬性和方法;
2.降低程式碼的靈活性。子類必須擁有父類的屬性和方法,讓子類自由的世界中多了些約束
3.增強了耦合性。當父類的常量,變數和方法被修改時,必須需要考慮子類的修改,而且在缺乏規範的環境下,這種修改可能會帶來非常糟糕的結果—大量的程式碼需要重構