前言

在日常工作中,我們使用Java語言進行業務開發的時候,或多或少的都會涉及到設計模式,而運用好設計模式對於我而言,又是一個比較大的難題。為了解決、克服這個難題,筆主特別開了這個部落格來記錄自己學習的筆記和自己的理解,也歡迎對此有興趣的朋友一起來和筆主探討,共同學習。

一、軟體架構設計模式的七大原則

1、開閉原則

對擴充套件開放,對修改關閉。在程式需要擴充套件的時候,不能去修改原有的程式碼實現一個熱插拔的效果。簡而言之,就是用抽象構建架構,用實現擴充套件細節。

2、單一職責原則

不要存在多於一個導致類變更的原因。簡單來說,就是一個Class/Interface/Method只負責一項職責

3、依賴倒置原則

這個原則是開閉原則的基礎,是指設計結構程式碼時,高層模組不應該依賴於底層模組,二者應該依賴於抽象。抽象不應該依賴於細節,細節應該依賴於抽象。即:針對介面程式設計,依賴於抽象而不依賴於具體

4、介面隔離原則

使用多個介面,而不使用單一的介面,客戶端不應該依賴它不需要的介面。儘量的細化介面的職責,降低類的耦合度

5、迪米特法則

又被成為最少知道原則,指的是一個物件應該對其他物件保持最少的瞭解。一個實體類應當儘量少地和其他實體之間發生相互作用,使得系統模組相互獨立。形象來說就是:只和朋友交流,不和陌生人說話。

6、里氏替換原則

如果說實現開閉原則的關鍵步驟就是抽象化,那麼基類(父類)和子類的繼承關係就是抽象化的具體實現,所以里氏替換原則就是對實現抽象化的具體步驟的規範。即:子類可以擴充套件基類(父類)的功能,但不能改變父類原有的功能。

7、合成複用原則

儘量使用物件組合/聚合,而不是使用繼承達到軟體複用的目的。可以使系統更加的靈活,降低類與類之間的耦合度,一個類的變化對於其他類來說影響相對較少。

繼承我們稱之為白箱複用,相當於把實現的細節暴露給子類,組合/聚合 也成為黑箱複用,對類之外的物件是無法獲取到實現細節的。

二、開閉原則詳解

對擴充套件開放,對修改關閉。在程式需要擴充套件的時候,不能去修改原有的程式碼實現一個熱插拔的效果。簡而言之,就是用抽象構建架構,用實現擴充套件細節。

光看理論是不行的,這樣的話我們只能是有一個模糊的認識,對具體的細節不太能看得清,我們先來舉一個例子看一看它是怎麼使用的:

例:假如我們居住的附近有一個小超市開業了,裡面有各種的商品。老闆想找你幫忙做一個超市商品的管理系統,那麼針對超市眾多商品的情況,我們首先應該會想到建立一個類來顯示商品的基本資訊:價格、名稱等, 針對此,我們先來建立一個介面:

/**
* 商品基本資訊 介面
*/
public interface Goods {
/**
* 商品的價格
*/
void getPrice(); /**
* 商品的名稱
*/
void getName();
}

我們發現超市裡有薯片販賣,我們再來寫一個薯片的類來實現這個介面,同時標明薯片的名稱和價格:

/**
* 樂事薯片
*/
public class Crisps implements Goods{
@Override
public void getPrice() {
System.out.println("商品的價格:9.9 RMB");
} @Override
public void getName() {
System.out.println("商品的名稱:樂事薯片");
}
}

老闆說以後還會有面包出售,那我們再來建立一個類來表明麵包的基本資訊:

/**
* 麵包
*/
public class Bread implements Goods{
@Override
public void getPrice() {
System.out.println("商品的價格:5.5 RMB");
} @Override
public void getName() {
System.out.println("商品的名稱:麵包");
}
}

等把這一切做好後,老闆說因為新店剛剛開業,沒有什麼人氣,就想前期通過薯片打折的方式來吸引人氣(薯片打六折),這個時候我們想到的是:

1、修改Crisps類中的getPrice()方法,但這會有一定的風險,可能會影響其他地方的呼叫結果。那麼這個方法就可以pass掉。

2、在Goods介面中再加一個方法獲取打折後的價格,但最後發現Bread類也需要去實現這個方法,但是麵包並沒有打折,這就對介面其他的實現類造成了影響,顯然不可取。

3、在Crisps類中再加入一個方法來獲得打折後的薯片價格,但這樣可能會改變Crisps類的結構,可能會造成不必要的麻煩,而且開閉原則的基礎就是:擴充套件程式的時候不能去修改原有的程式碼。那麼這個方法也被pass。

4、在增加一個類去繼承Crisps類,在子類中增加一個方法獲取打折後的價格,這樣通過子類我們可以獲取到商品的名稱,打折前的價格,打折後的價格,也不會改變Crisps類原有的結構,符合我們的規範,那我們再來編寫一個類。

/**
* 薯片的子類
*/
public class CrispsDisCountPrice extends Crisps { /**
* 打折後的價格
*/
public void getDisCountPrice(){
System.out.println("打折後的價格:"+ 9.9*0.6 +" RMB");
}
}

我們來看一下類的結構圖:

Crisps類和Bread類是介面Goods的實現類,而CrispsDisCountPrice類繼承了Crisps類。

寫個測試類測試一下:

public class Test {
public static void main(String[] args) {
Bread bread = new Bread();
CrispsDisCountPrice crisps = new CrispsDisCountPrice();
bread.getName();
bread.getPrice();
crisps.getName();
crisps.getPrice();
crisps.getDisCountPrice();
}
}

結果:

最後

學習設計模式不能只理解於理論,要根據例子理解才能更加的清晰、透徹。接下來的幾篇部落格,我會將設計模式剩下的六個原則都一一說明,並舉一例子。講完七大原則後,會重點解析我們常說的23種設計模式。這是我學習記錄的一個過程,謝謝!