設計模式七大原則
設計模式概述
設計模式就是對軟件設計過程中存在的普遍問題,所提出的解決方案。能夠很好的解決一些常見的問題。
設計模式的最終目的就是:高內聚低耦合
- 代碼重用性:相同功能的代碼,不需要多次編寫
- 代碼可讀性:編程規範性,便於其他程序員閱讀
- 代碼可擴展性:當增加新的功能後,對原來功能沒有影響
七大原則
一、單一責任原則
顧名思義,我們設計的類儘量負責一項功能,這樣不容易造成代碼混亂,避免出現一些bug。
反例:
Single類:
public class single{
public static void main(String[] args){
People people = new People;
people.run("老師");
people.run("學生");
people.run("校長");
}
}
People類:
public class People{
void run(String type){
System.out.println(type+"給學生上課");
}
}
這樣會造成,不管是老師、學生、校長都會調用這個方法,因爲People不止負責了一個功能,所以該設計有問題。
改進
對於上面的例子,我們採用單一職責原則重寫一下,將People拆分成三個類,分別是學生、老師、校長。讓他們負責各自的功能,使其互相不影響。如果想對學生做限制,那麼只需要對學生類進行修改。
優化
或者可以將上面People分爲三個方法,每個方法對應不同的人員,將單一職責落在方法層面而不是類層面
優缺點
優點:
- 降低類的複雜度,一個類只負責一個職責
- 提高代碼的可讀性,邏輯清楚明瞭
- 降低風險,只修改一個類,並不影響其他類的功能
缺點:
- 代碼增多(可以將單一職責落在方法層面進行優化)
二、接口隔離原則
類不應該依賴不需要的接口,接口儘量小顆粒劃分、如果將多個方法合併爲一個接口,再提供給其他系統使用的時候,就必須實現該接口的所有方法,那些方法是根本不需要的,造成使用者的混淆
三、依賴倒轉原則
- 高層模塊不應該依賴底層模塊,二者都應該依賴接口或抽象類
- 其核心就是面向接口編程
- 依賴倒轉原則主要是基於如下的設計概念:相對於細節的多變性,抽象的東西要更加穩定的多,以抽象爲基礎搭建的框架更加穩定
- 抽象指接口或抽象類,細節指具體的實現類
反例:
- 設計圖
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-QaVgzavi-1593420283358)(https://raw.githubusercontent.com/iszhonghu/Picture-bed/master/img/20200629150212.png)]
Potato類
public class Potato{
public void run(){
System.out.println("買了土豆");
}
}
People類
public class People{
public void bug(Potato potato){
potato.run();
}
}
Test類
public class Test{
public staticvoid main(String[] args){
People people = People();
people.bug(new Potato());
}
}
改進
上述在反例中,如果不想買土豆,想買其他的蔬菜,就比較麻煩還需要改People方法,這就是代碼中的模塊和模塊之間的耦合性太高。
- 改進後的設計圖
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-QuXNMN0h-1593420283360)(https://raw.githubusercontent.com/iszhonghu/Picture-bed/master/img/20200629150342.png)]
這樣我們從底層的類抽象出一個接口類,其直接和高層進行交互,而底層的一些類則不參與,這樣能降低耦合度,提高穩定性。
- Vegetables類
public interface Vegetables{
public void run();
}
-
Potato類
public class Potato implements Vegetables{ public void run(){ System.out.println("買了土豆"); } }
-
Tomato類
public class Tomato implements Vegetables{
public void run(){
System.out.println("買了番茄");
}
}
- People類
public class People{
public void bug(Vegetables vegetable){
vegetable.run();
}
}
- Test類
public class Test{
public static void main(String[] args){
People people = new People();
people.bug(new Potato());
people.bug(new Tomato());
}
}
總結
該原則的重點在於”倒轉“,要從底層往上思考,儘量抽象抽象類和接口。此例子很好的解釋了”上層模型不能依賴底層模塊,應該都依賴於抽象“。
四、里氏替換原則
主要是闡述了對繼承extend的一些看法
繼承的優點:
- 提高代碼的可重用性,子類也有父類的屬性和方法
- 提高代碼的可擴展性,子類有自己特有的方法
繼承的缺點:
- 當父類發生改變的時候,要考慮子類的修改
里氏替換原則是繼承的基礎,只有當子類替換父類時,軟件功能仍不受影響,才說明父類真正被複用了。
原則一:
子類必須實現父類的抽象方法,但不得重寫(覆蓋)父類的非抽象的方法
原則二:
子類中可以增加自己特有的方法。
原則三;
當子類覆蓋或實現父類的方法時,方法的前置條件(即方法的形參)要比父類方法的輸入參數更加寬鬆。
五、開閉原則
前面四個原則都是爲了開閉原則做鋪墊,其是最基礎、最重要的設計原則,核心爲對擴展開發,對修改關閉、簡單來說,通過擴展軟件的行爲來實現變化,而不是通過修改來實現。
六、迪米特原則
介紹:
- 一個對象應該對其他對象保持最少的瞭解。
- 類與類關係越密切,耦合度越大
- 一個類對自己依賴的類知道的越少越好。也就是說,對於被依賴的類不管多麼複雜,都儘量將邏輯封裝在類的內部。對外除了提供的public 方法,不對外泄露任何信息
- 迪米特法則還有個更簡單的定義:只與直接(熟悉)的朋友通信
直接(熟悉)的朋友:每個對象都會與其他對象有耦合關係,只要兩個對象之間有耦合關係, 我們就說這兩個對象之間是朋友關係。耦合的方式很多,依賴,關聯,組合,聚合等。
其中,我們稱出現成員變量,方法參數,方法返回值中的類爲直接的朋友,而出現在局部變量中的類不是直接的朋友。也就是說,陌生的類最好不要以局部變量 的形式出現在類的內部。
七、合成複用原則
- 儘量使用合成/集合,不要用繼承
- 如果使用繼承,會使得耦合性加強,儘量作爲方法的輸入參數或類的成員變量,這樣可以避免耦合
最後
- 如果覺得看完有收穫,希望能給我點個贊,這將會是我更新的最大動力,感謝各位的支持
- 歡迎各位關注我的公衆號【java冢狐】,專注於java和計算機基礎知識,保證讓你看完有所收穫,不信你打我
友。也就是說,陌生的類最好不要以局部變量 的形式出現在類的內部。
七、合成複用原則
- 儘量使用合成/集合,不要用繼承
- 如果使用繼承,會使得耦合性加強,儘量作爲方法的輸入參數或類的成員變量,這樣可以避免耦合
最後
- 如果覺得看完有收穫,希望能給我點個贊,這將會是我更新的最大動力,感謝各位的支持
- 歡迎各位關注我的公衆號【java冢狐】,專注於java和計算機基礎知識,保證讓你看完有所收穫,不信你打我
- 如果看完有不同的意見或者建議,歡迎多多評論一起交流。感謝各位的支持以及厚愛。