天天看點

Singleton 單例模式的三種實作

一、什麼是Singleton?

Singleton 指的是僅僅隻能被執行個體化一次的類。(通常用來代表本質上唯一的系統元件:視窗管理器,檔案系統)

二、Java 1.5 之前的兩種實作方法

構造器保持為私有的

,然後導出

公有的靜态成員

public static

),允許用戶端通路這個類的唯一的執行個體。私有的構造器(

private Dog(){...}

)僅會被調用一次去進行執行個體化,這保證了類隻能被執行個體化一次;

  1. 公有的靜态成員是一個

    final域

    (調用:

    Dog.INSTANCE

//Singleton with public final field
public class Dog {
	//公有靜态執行個體(final域保持執行個體唯一)
	public static final Dog INSTANCE = new Dog();
	//私有的構造器
	private Dog() {...}
	public void sleep() {...}
}
           
  1. 公有的靜态成員是一個

    靜态工廠方法

    (調用:

    Dog.getInstance

//Singleton with static factory
public class Dog {
	//公有靜态執行個體(final域保持執行個體唯一)
	public static final Dog INSTANCE = new Dog();
	//私有的構造器
	private Dog() {...}
	//靜态方法
	public static Dog getInstance() {return INSTANCE;}
	public void sleep() {...}
	
	//readResolve方法,保證signleton的實作
	private Object readResolve() {
		//傳回真執行個體,并讓垃圾回收器處理假執行個體
		return INSTANCE;
	}
}
           

一般都會使用第二種方法,調用靜态方法

Dog.getInstance

,每次調用都會傳回同一個對象引用,是以保持了執行個體的唯一性。

注意:

  • public 和 private 的構造器可以多次調用;
  • 享有特權的用戶端可以借助

    AccessibleObject.setAccessible

    方法,通過反射機制來調用私有構造器。(抵禦方法:修改構造器,在第二次被調用時抛異常)
  • 為了實作序列化,隻implement Serializabled是不夠的,還得聲明所有執行個體域都是瞬時(transent,文末有解釋)的,并在Dog類裡提供一個

    readResolve

    方法。否則,每次反序列化的時候,都會新建立一個執行個體(假冒的Dog類)

三、java 1.5之後 —— 最佳實作方法(enum)

  1. 編寫一個包含

    單個元素的枚舉類型enum

    ,而不是class類
//Enum singleton - the preferred approach
public enum Dog {
	INSTANCE;
	public void sleep () {...}
}
           

這種方法在功能上與公有域方法相近,但更加簡潔,提供了

序列化機制

,即使面對複雜的序列化或者發射攻擊,也絕對防止了多次執行個體化。

瞬時(transient):

一個持久化類的執行個體可能處于三種不同的狀态中的某一種。這三種狀态的定義則與所謂的持久化上下文(persistence context)有關。Hibernate的Session對象就是這個所謂的持久化上下文。

瞬态(transient)

該執行個體從未與任何持久化上下文關聯過。它沒有持久化辨別(相當于主鍵值)。
           

持久化(persistent)

執行個體目前與某個持久化上下文有關聯。它擁有持久化辨別(相當于主鍵值),并且可能在資料庫中有一個對應的行。對于某一特定的持久化上下文,Hibernate保證持久化辨別與Java辨別(其值代表對象在記憶體中的位置)等價。
           

托管(detached)

執行個體曾經與某個持久化上下文發生過關聯,不過那個上下文被關閉了,或者這個執行個體是被序列化(serialize)到另外的程序。它擁有持久化辨別,并且在資料庫中可能存在一個對應的行。對于托管狀态的執行個體,Hibernate不保證任何持久化辨別和Java辨別的關系。
           

參考1、《Effictive Java》