1. 程式人生 > 實用技巧 >常用設計模式

常用設計模式

單例模式

定義和特點

定義:所謂單例,就是整個程式有且僅有一個例項。

特點:

  • 類構造器私有
  • 持有自己型別的屬性
  • 對外提供獲取例項的靜態方法

優缺點

優點:

  1. 提供了對唯一例項的受控訪問;
  2. 節省系統資源。由於系統中記憶體只存在一個物件,因此可以節約資源的資源,對於一些繁瑣的建立和銷燬的物件,單例模式無意中可以提高系統的效能;
  3. 單例模式允許可變的數目的例項,使用單利模式進行擴充套件,使用控制單利物件相似的方法可以獲取指定個數的例項,及解決了單利物件共享過多,而有損效能的問題。

缺點:

  1. 由於單例模式不是抽象的,所有可擴充套件性比較差。
  2. 單例類,職責過重,在一定程度上違背了單一職責原則
  3. 濫用單例將帶來一些負面問題,如為了節省資源將資料庫連線池物件設計為的單例類,可能會導致共享連線池物件的程式過多而出現連線池溢位;如果例項化的物件長時間不被利用,系統會認為是垃圾而被回收,這將導致物件狀態的丟失。

餓漢式

public class Singleton {  
  	// 1.在類的內部建立自行例項,持有自己型別的屬性
    private static Singleton instance = new Singleton();
  	// 2.將建構函式私有化,不可以通過new的方式來建立物件
    private Singleton (){}  
  	// 3.提供獲取唯一例項的靜態方法
    public static Singleton getInstance() {  
    	return instance;  
    }  
}

一上來就建立物件,執行緒安全,比較常用,但是容易產生垃圾,因為如果該例項從始至終都沒被使用過,則會造成記憶體浪費

懶漢式

public class Singleton {  
  	//持有自己型別的屬性,先不建立物件,用到時再建立
    private static Singleton instance;  
  	//構造器私有化
    private Singleton (){}  
  	//對外提供獲取例項的靜態方法(多執行緒環境下加鎖)
    public static synchronized Singleton getInstance() { 
      	// 用到時如果這個物件引用為null,我們就建立並返回出去
    	if (instance == null) {  
        	instance = new Singleton();  
    	}  
    	return instance;  
    }  
}

執行緒不安全,使用synchronized加鎖;但是直接在方法上加鎖的方式其實不夠好,在多執行緒環境下效能會比較低,下面是雙重檢測機制(DCL)懶漢式

雙重檢測機制(DCL)懶漢式

public class Singleton {  
    private volatile static Singleton singleton;  // volatile實現記憶體可見性
    private Singleton (){}  
    public static Singleton getSingleton() {  
    	if (singleton == null) {  //此處判斷是為了提高效能
        	synchronized (Singleton.class) {  //同步程式碼塊進行執行緒加鎖
        		if (singleton == null) {  
            		singleton = new Singleton();  
        		}  
        	}  
    	}  
    return singleton;  
    }  
}

雙重檢查模式,進行了兩次的判斷,第一次是為了避免不要的例項,第二次是為了進行同步,避免多執行緒問題。由於singleton singleton = new Singleton()物件的建立在JVM中可能會進行重排序,在多執行緒訪問下存在風險,使用volatile修飾signleton例項變數有效,解決該問題。

靜態內部類懶漢式

public class Singleton { 
    private Singleton(){
    }
      public static Singleton getInstance(){  
        return Inner.instance;  
    }  
    private static class Inner {  
        private static final Singleton instance = new Singleton();  
    }  
} 

只有第一次呼叫getInstance方法時,虛擬機器才載入 Inner 並初始化instance ,只有一個執行緒可以獲得物件的初始化鎖,其他執行緒無法進行初始化,保證物件的唯一性。目前此方式是所有單例模式中最推薦的模式,但具體還是根據專案選擇。


眾所周知,單例模式是建立型模式,都會新建一個例項。那麼一個重要的問題就是反序列化。當例項被寫入到檔案到反序列化成例項時,我們需要重寫readResolve方法,以讓例項唯一。

private Object readResolve() throws ObjectStreamException{
        return singleton;
}

介面卡模式

定義

介面卡主要用於介面的轉換或者將介面不相容的類物件組合在一起形成對外統一介面,是一種結構性模式,其本質是是一箇中間件,適用於類及其物件。

適用場景

  1. 想用一個已經存在的類,但其介面不符合需求;
  2. 想建立一個可以複用的類,該類可以與其他不相關的類協同工作;
  3. 想使用一些已經存在的子類,但是不能對每一個都進行子類化以匹配它們的介面(僅適用於物件Adapter)。物件介面卡可以適配他的父類介面。

優缺點

優點

  1. 提高了類的複用;
  2. 組合若干關聯物件形成對外提供統一服務的介面;
  3. 擴充套件性、靈活性好。

缺點

  1. 過多使用適配模式容易造成程式碼功能和邏輯意義的混淆。
  2. 部分語言對繼承的限制,可能至多隻能適配一個適配者類,而且目標類必須是抽象類。