1. 程式人生 > >最通俗易懂--設計模式之七大原則

最通俗易懂--設計模式之七大原則

我寫的這一系列設計模式,可能會圍繞Java+Android來舉例,但是不影響閱讀。

設計模式是什麼?
設計模式是廣大程式設計師長年累月的經驗總結。這門課也不是太容易,我儘量理解,也儘量說的簡潔並通俗易懂,共同學習。
設計模式有什麼用?
優化你的程式碼,讓程式碼可讀性強,適用性高,軟體體系更加靈活。
回看一下自己的程式碼有沒有一種牽一髮而動全身的害怕,稍微更改一點就要崩潰,設計模式就是來解決這些問題的。
設計模式重要嗎?
如果現在還不瞭解他是幹什麼的,看看自己寫的程式碼,看看開發文件的程式碼,要認真起來:我以後肯定要寫到那樣的程式碼體系。未優化程式碼+設計模式=開發文件程式碼格式。
學習設計模式要準備什麼?


1我愛設計模式。
2.我愛設計模式。
3.我愛設計模式。

設計模式七大原則:
1. 單一職責原則/Single Responsibility Principle(自己只負責自己這一類的事)
2. 開閉原則/Open Close Principle(確定正確不輕易更改,在此基礎擴充套件功能實現更改)
3. 里氏代換原則/Liskov Substitution Principle(父類可適用的地方子替換成子類可用且不報錯)
4. 依賴倒置原則/Dependence Inversion Principle(針對抽象和介面程式設計,不依賴具體類)
5. 介面隔離原則/InterfaceSegregation Principles(把使用的介面拆分細化)
6. 迪米特原則/Law of Demeter(只與直接朋友聯絡)
7. 合成複用原則/Composite Reuse Principle(多使用合成/聚合方式,儘量不使用繼承)

1. 單一職責原則/Single Responsibility Principle(自己只負責自己這一類的事)
我們看一些專業化的名詞的時候,一般來說他的命名是他所描述內容的精華概括。單一職責原則的重點就是單一,舉一個例子,我們需要設計一個類ImageLoader:他的功能主要是網路下載和本地快取。一般我們怎麼寫?反正我肯定會這樣做:把他們都放在一個類中,實現了所有的功能,也只有一個類,簡潔方便。但是,單一職責的原則是這個類應該是一組相關性很高的方法或函式的集合。所以網路下載和本地快取邏輯上應該為兩個操作,故應設計兩個類來分別實現。這就是單一職責原則。

2. 開閉原則/Open Close Principle(確定正確不輕易更改,在此基礎擴充套件功能實現更改)


開閉原則講究一開一閉,對擴充套件開放,對修改封閉。我們寫程式碼最終目的是什麼,是完成整個系統功能嗎?不,這只是一個副產品,我們的主要目的應該設定為讓整個系統穩定、靈活、適用性強。對於開閉原則,舉一個例子:假如你寫好了一個購物的程式碼類而且已經上線投入使用,現在按需求要在此程式碼類上加入購物車的功能,這樣怎麼做?或許你會選擇修改那個以上線的程式碼,然後重新發布,但是考慮到修改的易出錯性,而且你的功能設計正在投入使用,萬一出錯那將是要付出很大代價的。所以開閉原則的定義就是:對購物程式碼類進行擴充套件而不是修改它擴充套件可以實現原有的所有功能並加入自己的新方法或函式,所以這樣做安全性大大提高,在你測試的時候就不必擔心原來的程式碼會有大Bug(因為我們沒有對他做修改)。

3. 里氏代換原則/Liskov Substitution Principle(父類可適用的地方子替換成子類可用且不報錯)
這個命名是以原則提起人姓氏命名的,是一種紀念形式,不必過多追究。代換是這個原則的寓意所在,所有引用基類的地方都可以代換為他的子類。為什麼父類可以代換為子類?里氏代換原則依賴於面向物件的繼承和多型兩大特性。我們寫了父類class A其中有方法 void a(),如果再寫一個類class B extends A那我們在類B中是不是要實現A的所有方法也就是void a(),所以我們在使用類A的地方完全可以用類B替換,而且不會報錯,因為class B擁有class A的全部特性。

4. 依賴倒置原則/Dependence Inversion Principle(針對抽象和介面程式設計,不依賴具體類)
我們設計了一個圖片快取的類ImageCache,起始的設計實現是儲存到手機記憶體,然後有需求需要儲存到記憶體卡–>改ImageCache類,過幾天又有需求要儲存到外接硬碟–>改ImageCache類,計劃跟不上變化….–>又改ImageCache類……這麼做好累吧。。。而且一直在更改類,有沒有違反了開閉原則。所以呢,針對抽象介面程式設計就要求我們設計一個ImageCache介面:

public interface ImageCache{
    public Bitmap get(String url);
    public void put(String url,Bitmap bmp);
}

這樣做,我們需要更改需求的時候呢,只需要更改Url儲存地址這不就行了,不必麻煩去改程式碼了。

5. 介面隔離原則/InterfaceSegregation Principles(把使用的介面拆分細化)
按字面意思就是把接分割。客戶端所依賴的介面不應該依賴他不需要的介面。
比如我們設計一個介面:

public interface mDownload{
 public void ImageDownload(String url);//圖片下載功能
 public void imageCache(String url,Bitmap bmp);//圖片快取功能
}

然後我們設計的Image類需要實現圖片下載功能,不需要快取,然而我們實現介面就必須實現兩個方法:

public class Image implements mDownload{
  public void ImageDownload(String url){
//相關程式碼片
}
  public void ImageCache(String url,Bitmap bmp){}
}

弊端其一是暴露了介面的結構,資訊洩露。其二是須實現不需要的方法。
這還只是兩個方法,如果介面方法過多,那豈不是大麻煩…..
所以介面隔離原則要求介面細化,這樣設計:

//第一個介面
public interface mDownload{
public void ImageDownload(String url);
}
//第二個介面
public interface mIMageCache{
public void ImageCache(String url,Bitmap bmp);
}

程式碼實現我們可以這樣寫:
需要下載功能的:

public class Image implements mDownload{
 public void ImageDownload(String url){
//相關程式碼片
  }
}

需要快取功能的:

public class Image implements mImageCache{
  public void ImageCache(String url,Bitmap bmp){
//相關程式碼片
  }
}

需要下載和快取功能的:

public class Image implements mDownload,MImageCache{
  public void ImageDownload(String url){
//相關程式碼片
  }
   public void ImageCache(String url,Bitmap bmp){
//相關程式碼片
  }
}

6. 迪米特原則/Law of Demeter(只與直接朋友聯絡)
迪米特原則也稱為最少知道原則,類與類之間可以比作我們生活中的的人與人。當你需要買一張火車票時,你下命令給同學去幫你買-_-!同學呢,或者坐公交去火車站,或者打的去火車站,或者網上幫你訂購。。。然而你只要得到他給你反饋的結果,買到或沒有或出了異常,而不關心他是怎麼實現這件事情的(現實中肯定不是這樣的),這就是最少知道原則,知道多了,也就是你知道他實現的方法,其一是資訊洩露,其二是事情變複雜了,或許他實現了getHurt()方法,受傷了,你帶他去醫院。。。你本來只要實現help()讓同學幫忙的方法,最後卻實現了很多事,讓你的類變得雍容複雜。所以這就是最少知道法則。

7. 合成複用原則/Composite Reuse Principle(多使用合成/聚合方式,儘量不使用繼承)
合成是強烈的關聯,聚合是部分關聯。合成關係中部分與整體生命週期相同,脣亡齒寒。聚合中則不一定會一榮俱榮,一損俱損。重點是優先使用物件組合而不是繼承。繼承的侷限性在於1.暴露全部結構資訊。2.匯入時是靜態匯入無法修改。例如:我們在網路條件下獲取圖片資料時需要聯網,這個連線操作可以設計一個類:

public class Connect{
  public void getConnect(String url){
  //connect相關程式碼
  }
}

我們實現連線時:

public class ImageDownload extends Connect{
  public void getConnect(String url){
  //相關程式碼片
  }
}

如果現在我們產品升級了,需要繼承其他類,這就無法實現了,然後根據合成複用這樣改:

public class Connect{
  public void getConnect(String url){
  //connect相關程式碼
  }
}

繼承其他類Other時同時保留網路連線的功能:

import com.position.Connect;//根據實際路徑匯入Connect類
public class ImageDownload extends Other{
  public void getOther(){
  //Other類相關程式碼片
  }
  //網路連線功能這樣實現
  Connect net = new Connect();
  net.getConnect(String url);
}

這樣做安全,方便,靈活多用。當然也並不是完全否定繼承,組合和繼承一起使用,提高工作效率。
什麼時候用集成合適?在Android中當你需要自定義控制元件的時候,比如自定義Button這個時候繼承Button在他的靜態方法中覆寫自己需要自定義的地方,這種場景需求方向和功能相對固定,而且繼承後自己可以省出大量時間做自定義工作,而不用一個一個寫需要實現的方法等。

好了,至此設計模式七大原則告一段落,我寫的不是最官方,但確保通俗易懂,有錯就改,共同勉勵,加油!接下來23種設計模式,一個一個來。