設計模式---六大原則
背景:聽說設計模式是進入BAT的必經之路。
First、何謂設計模式:
設計模式(Design Pattern)是一套被反覆使用、多數人知曉的、經過分類的、程式碼設計經驗的總結。
設計模式的好處&學習目的:
1、為了程式碼可重用行、讓程式碼更易被他人理解、保證程式碼的可靠性、使程式碼編寫真正實現工程化;
2、設計模式便於我們維護專案,增強系統的健壯性和可擴充套件性;
3、設計模式還可以鍛鍊碼農的設計思維、昇華程式碼質量等。
六大指導原則:
程式設計模式有六大基本指導原則,但規則畢竟都是人定的,So我們要靈活遵守、靈活運用這六大原則。
一、開-閉原則:
1、開閉原則顧名思義就是對修改關閉,對擴充套件開放;
2、開閉原則是六大原則的核心,即我們之後做的任何改變都不需要修改原有的程式碼,只需要加入一些新的實現即可達到目的;
3、開閉原則也是任何一個系統設計期望達到的理想境界。
二、單一職責原則:
單一職責即每個類都只負責單一的功能,莫要太貪心,除此之外儘量把一個類的功能完善到極致,可以用final來修飾的程度。下面就有一個例子類Scientific 從一個檔案中讀取兩個數,並返回兩者之和,如此設計可以很明顯的看到它們之間的職責問題存在太多耦合了。如圖:
上圖中顯示的 Scientific 類並沒有錯,但是我們要是讀取檔案的地址改變了呢?要是結果改為兩者之差、 兩者之積或 兩者之商或者是 兩者之模呢?然後,我們需要複製許多份相同的程式碼,想想這種設計就不合理;這時我們就要考慮下“ 單一職責原則 ”,分離出一個類ReadFile 來讀取資料,再分離出一個類DesignScientific 對讀取到的資料進行處理(加減乘除等)。
1 import java.io.BufferedReader; 2 import java.io.FileReader; 3 public class ReadFile { 4 5private int numOne; 6private int numTwo; 7 8public ReadFile(String path) throws Exception { 9BufferedReader br = new BufferedReader(new FileReader(path)); 10numOne = Integer.valueOf(br.readLine()); 11numTwo = Integer.valueOf(br.readLine()); 12System.out.println("numOne is: "+numOne+" && "+"numTwo is: "+numTwo); 13} 14 15public int getNumOne() { 16return numOne; 17} 18 19public int getnumTwo() { 20return numTwo; 21} 22 }
如此,將一個類拆為兩個,既不會有那麼多重複的程式碼,也多了跟多結果的選擇性,也恰恰體現了單一職責原則是我們設計模式最應該遵守的原則之一。
三、里氏替換原則:
里氏替換原則具體指的是一個子類可以在替換掉其父類後正常工作,也就是自類不應該重寫父類的方法,其主要作用是規範繼承是子類的一些書寫規則,主要目的是保持父類方法不被覆蓋。
1、子類可以實現父類的抽象方法,但不能覆蓋父類的抽象方法(要不重新寫給類算了,幹嘛要繼承);
2、子類中可以增加自己特有的方法;
3、當子類覆蓋或實現父類方法時,方法的前置條件(方法的形參)要比其父類方法的輸入引數更寬鬆(如:fun ( ArrayLIst , list) VS fun(List, list) );
4、當子類的方法實現父類的抽象方法時,方法的後置條件(方法的返回值)要比其父類更嚴格。
四、介面隔離原則:
介面隔離原則也叫做介面最小化原則,指的是一個介面擁有的行為應該儘可能的最小。
1、如果設計的時候沒有考慮到介面隔離原則,就會出現一個類實現了一個介面但實現類中只有個別的方法實現了其他方法都是空的狀況,導致強制實現了不得不實現而又本不該實現的方法,而最終也一直沒有呼叫過此方法,造成資源浪費;
2、比如我們設計一個手機Mobile的介面時,就要考慮手機哪些屬性時必須的,要讓該介面儘量最小最細化,即只要是手機就必須要具備的屬性。
沒有遵守介面隔離原則的Mobile介面設計:
1 public interface Mobile { 2public void call();//手機可以打電話 3public void sendMessage();//手機可以發簡訊 4public void weChat();//手機可以上微信weChat? 5}
上述Mobile介面很明顯不是一個手機必須具備的功能屬性,那麼什麼的Mobile介面就不是最小介面,因為非智慧手機就只可以打電話和發簡訊,而上微信就是智慧手機的專屬特性,如此就會有多餘的實現方法,可以做如下修改,充分考慮 介面隔離原則 。
1 public interface SmartPhone extends Mobile{ 2public void weChat();//智慧手機的介面就可以加入這個方法了 3}
五、依賴倒置原則:
這個原則描述的是高層模組不該依賴於低層模組,兩個模組都應該依賴依賴於抽象,抽象不應該依賴於細節,細節應該依賴於抽象。因為實現都是易變的,只有抽象是穩定的,所以當我們依賴於抽象是,實現的變化就不會影響客戶端的呼叫;就比如上面“ 單一職責 ”中的計算器的例子,計算器其實是依賴於資料讀取類的,這樣設計還是有一些缺陷,因為若是當資料不是在檔案裡,而是在資料庫當中呢?這時候為了不影響現有的程式碼,只能將ReaderFile類整個大改,或是新增一個DBReader類,把程式程式碼中所有使用到ReaderFile讀取到地方替換成DBReader,這樣做勉強可以接受,但是仍然達不到可複製化的標準;若是資料讀取有的是從資料庫、有點是從XML檔案、有的是從網路或是從鍵盤輸入讀取,這時就有充分考慮依賴倒置原則。
1 public interface Reader { 2//依賴倒置抽象出的一個抽象介面 3public int getA(); 4public int getB(); 5 }
依賴倒置原則 讓我們抽象出一個抽象類或者介面,來表述資料讀取行為,然後讓上面所有的讀取方式所實現的類都實現該介面,客戶端方面只使用我們定義好的介面,當我們的實現變化時,我們只需設定下不同的實際型別就OK了,這樣設計對於系統的擴充套件行將會是一個巨大的提升;這樣設計的話,計算器就依賴於一個很穩定的抽象介面,之後不論是從哪裡讀取資料,兩個獲取資料的方法都不會改變;無論是DBReader、XMLReader、NetReader或是OutPutStreamReader之類的都可以實現Reader這個抽象介面,不管是從哪裡讀取資料都OK,因為我們不需要關心這個,只要可以從Reader介面中獲得A和B的值就OK了;同時,依賴於抽象也體現了JAVA語言的動態特性。
六、迪米特原則:
迪米特原則也稱最小知道原則,就是一個類儘量不應該知道(包括)其他類太多的東西,不要和其他類有太多的交集。該原則的制定的終極目的就是解耦,即將細節全部高內聚於類的內部,其他的類只需知道這個類主要提供的功能就OK了,減少不必要的依賴,高聚合低耦合。