【設計模式筆記】(零) 設計模式六大原則

1.單一職責原則(Single Responsibility Principle,縮寫SRP)

單一職責原則,就一個類而言,應該只有一個引發它變化的緣由。簡單說,一個類應該是一組高度相關的函數、數據的封裝;也就是高內聚。編程

下面代碼爲 ImageLoader(圖片加載)類的代碼緩存

public class ImageLoader{
	//圖片緩存
	LruCache<String,Bitmap> mImageCache;
	//線程池,線程數量爲CPU的數量
	ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProessors());
	
	public ImageLoader(){
		initImageCache();
	}
	
	private void initImageCache() {
   		//省略...         
   }
    
   //顯示圖片
   public  void displayImage(final String url, final ImageView imageView) {
   		//省略... 
   }
    
   //下載圖片
   public  Bitmap downloadImage(String imageUrl) {
        //省略... 
        return bitmap;
   }
}
複製代碼

這裏能夠看出來 ImageLoader 類做用有初始化圖片緩存、顯示圖片、下載圖片,顯然顯示圖片和下載圖片兩個方法與初始化圖片緩存方法相比做用就顯得有些不相關。也就是不符合單一職責原則。按照邏輯進行分拆以後獲得ImageLoaderImageCache兩個類。ImageLoader負責圖片加載邏輯,ImageCache負責處理圖片緩存邏輯,這樣職責就清楚了,當與緩存相關的邏輯須要改變時,不須要修改ImageLoader類,而圖片加載的邏輯須要修改時也不會影響到緩存處理邏輯。bash

image

ImageLoader代碼修改以下所示:框架

/** 圖片加載類 */
public  class ImageLoader {
    //圖片緩存
    ImageCache mImageCache = new ImageCache() ;
    //線程池,線程數量爲CPU的數量
    ExecutorService mExecutorService = Executors.newFixedThreadPool (Runtime.getRuntime().availableProcessors());

    //加載圖片
    public  void displayImage(final String url, final ImageView imageView) {
        //省略... 
     }

    public  Bitmap downloadImage(String imageUrl) {
        //省略... 
        return bitmap;
    }
} 
複製代碼

而添加的ImageCache類用於處理圖片緩存,具體代碼以下:函數

public class ImageCache {
    // 圖片LRU緩存
    LruCache<String, Bitmap> mImageCache;

    public ImageCache() {
        initImageCache();
    }

    private void initImageCache() {
        //省略... 
    }

    public void put(String url, Bitmap bitmap) {
        mImageCache.put(url, bitmap) ;
    }

    public Bitmap get(String url) {
        return mImageCache.get(url) ;
    }
}
複製代碼

如何劃分一個類、一個函數的職責,每一個人都有本身的見解,這須要根據我的經驗、具體的業務邏輯而定。ui

2.開閉原則(Open Close Principle,縮寫OCP)

開閉原則是Java中最基礎的設計原則,知道咱們如何創建一個穩定的、靈活的系統。定義:軟件中得對象應該對於擴展是開放的,可是對於修改是封閉的。url

例如圖中MemonyCacheDiskCacheDoubleCache都實現了ImageCache接口,ImageLoader使用ImageCache處理緩存,就意味着ImageLoader能夠經過setImageCache()指定使用哪種緩存類型,可使三種緩存其中任意一種,同時不須要修改ImageLoader中的代碼。這也就是開閉原則的體現。spa

簡單地說,當軟件須要變化時,應該儘可能經過擴展的方式來實現變化,而不是經過修改已有的代碼來實現。「應該儘可能」4個字說明OCP原則並非說絕對不能夠修改原始類的,當代碼須要須要重構的時候要及時重構,使代碼恢復正常,而不是經過繼承等方式添加新的實現,這會致使類型的膨脹以及歷史遺留代碼的冗餘。線程

開發過程當中都沒有那麼理想的情況,所以,凡事也是須要結合具體狀況再作決定,目的是更穩定、更靈活同時保有原有的正確性。翻譯

3.里氏替換原則(Liskov Substitution Principle,縮寫LSP)

里氏替換原則,書上原話的定義簡直看不得(解釋的辣眼睛,徹底看不懂),簡單地說就是全部引用基類的地方必須能透明地使用其子類的對象。只要父類能出現的地方子類就能夠出現,並且替換爲子類也不會產生任何錯誤或異常,使用者可能根本就不須要知道是父類仍是子類。可是,反過來就不行了,有子類出現的地方,父類未必就能適應。其實就是:抽象。

上圖能夠看出,Window依賴於View,而ButtonTextView繼承View。這裏任何繼承自View類的子類均可以設置給show()方法,也就是里氏替換原則。經過里氏替換,就能夠自定義各式各樣的View,而後傳遞給Window,而且將View顯示到屏幕上。

里氏替換原則的核心原理是抽象,抽象又依賴於繼承這個特性,繼承的優缺點都至關明

優勢:

  • 代碼重用,減小建立類的成本,每一個子類都擁有父類的方法和屬性
  • 子類與父類基本類似,但又與父類有所區別
  • 提升代碼的可擴展性

缺點:

  • 繼承是侵入性的,只要繼承就必須擁有父類的全部屬性和方法
  • 可能形成子類代碼冗餘、靈活性下降,由於子類必須擁有父類的屬性和方法

事物老是具備兩面性,如何權衡利與弊都是須要根據具體場景來作出選擇並加以處理。

4.依賴倒置原則(Dependence Inversion Principle,縮寫DIP)

依賴倒置原則,說的就是一種特定的就形式,使得高層次的模塊不依賴於低層次的模塊的實現細節的目的,依賴模塊被顛倒了。依賴倒置原則的幾個關鍵點:

  • 高層模塊不該該依賴低層模塊,二者都應該依賴其抽象
  • 抽象不該該依賴細節
  • 細節應該依賴抽象

是否是以爲和沒說一個樣,至少我是這麼以爲的;繼續日後看才明白,所謂高層模塊就是調用端,低層模塊就是具體實現類。依賴倒置原則在 Java 語言中的表現就是:模塊間的依賴經過抽象發生,實現類之間不發生直接的依賴關係,經過接口抽象類產生依賴關係。什麼是依賴關係呢?其實就是相互之間的調用關係。歸納來講就是面向接口變成,或者是面向抽象編程。

其實依賴倒置原則主要目的就是解耦

依然可使用這張圖來表示,表達出來就是ImageLoaderMemonyCache等並無直接關係,甚至ImageLoader只須要實現ImageCache類或繼承其餘已有的ImageCache子類完成相應的緩存功能,而後將具體的實現注入到ImageLoader便可實現緩存功能的替換。這也是依賴倒置原則的體現。

5.接口隔離原則(Interface Segregation Principle,縮寫ISP)

接口隔離原則將很是龐大、臃腫的接口拆分紅爲更小的和更具體的接口;目的就是解耦。這個原則的作法和單一職責原則有點類似,就是說接口中得方法保持更高的相關性、儘可能少,避免掉不須要的方法。

舉個栗子,如今有一個帶有呼吸方法的接口,還有一個打鼾方法的接口;若是說,你把這兩個方法放到一個接口中,基本就是違背接口隔離原則,畢竟呼吸和打鼾沒有什麼緊密的相關性;不可能說我須要呼吸的時候必定須要打鼾吧!

6.迪米特原則(Law of Principle,縮寫LOP)

迪米特原則也稱爲最少知識原則(Least Knowledge Principle),定義:一個對象應該對其餘對象有最少的瞭解。通俗地講,一個類要對本身須要調用的類知道得最少,類的內部如何實現、如何複雜都與調用者(或依賴者)不要緊,調用者(或依賴者)只須要知道他須要的方法便可,其餘的不須要關心。類與類之間的關係越密切,耦合度越大;當一個類發生改變時,對另外一個類的影響也越大。

迪米特法則還有一個英文解釋是:Only talk to your immedate friends,翻譯過來就是:只與直接的朋友通訊。什麼叫作直接的朋友呢?每一個對象都必然會與其餘對象有耦合關係,兩個對象之間的耦合就成爲朋友關係,這種關係的類型有不少,例如組合、聚合、依賴等。

下圖是Volley框架中的DiskBasedCache類(實現Cache接口)和Cache接口的代碼

Volley中的Response緩存接口的設計。Cache接口定義了緩存類須要實現的最小接口,依賴緩存類的對象只須要知道這些接口便可。例如緩存的具體實現類DiskBasedCache,該緩存類將Response序列化到本地,這就須要操做File以及相關的類。

Volley的直接朋友就是DiskBasedCache,間接朋友就是mRootDirectory、mEntries等。Volley只須要直接和Cache類交互便可,並不須要知道File、mEntries等對象的存在。

文中有引用書本中得例子,也有根據本身理解舉的例子,若有不對還望指出。

相關文章
相關標籤/搜索