很多時候,您會需要Singleton模式,例如印表機管理,您希望程式中只能有一個Print Spooler,以避免兩個列印動作同時輸入至印表機中;例如資料庫管理,因為建立連線(Connection)物件會耗用資源,您希望程式中只能有一個 連線物件,所有其它的程式都透過這個物件來連線資料庫,以避免連線物件的重複開啟造成資源的耗用;例如系統程式屬性檔的讀取,您使用單一個物件來讀取屬性 內容,而程式的其它部份都向這個物件要求屬性資料,而不是自行讀取屬性資料。
以印表機設計為例,有的設計人員會採取全域變數的方式來建立實例,並在程式中隨機取用這個實例,Java雖然不支持全域變數,但透過將物件包裝在一個類別之中,也有人會採用這樣的寫法:
public class PrintSpooler {
public PrintSpooler() {
// ....
}
public Connection getSpooler(){
....
}
}
public class GlobalObject {
private PrintSpooler printSpooler;
public GlobalObject () {
printSpooler = new PrintSpooler();
...
}
public void getPrintSpooler() {
return printSpooler;
}
}
無論全域變數或是以上的例子,都無法保證只產生唯一個實例,您也許會注意不犯這個錯誤,但與您共同工作的夥伴也許會直覺的使用建構方法來產生一個 PrintSpooler實例。
Singleton模式可以保證一個類別只有一個實例,並提供一個訪問(visit)這個實例的方法。
一個Singleton實作即為Java中的java.lang.Runtime類別,每個Java程式執行時都有一個唯一的Runtime物件,可以透過它提供的靜態方法getRuntime()方法來取得這個物件,例如:
Runtime runtime = Runtime.getRuntime();
取得Runtime物件之後,您可以透過它進行一些外部命令的執行、進行垃圾處理等等指令,您可以開啟Runtime.java類別,開頭的幾行是這樣寫的:
public class Runtime {
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
// 以下略
}
上面結構即採用Singleton模式設計,其結構使用 UML 來表即如下所示:
如上所示的,Java使用 靜態工廠 來取得Runtime物件,其中Runtime的建構函式被宣告為private,這樣可以阻止其他人使用建構方法來建立實例;使用更一般化的表示單例的UML結構,如下圖所示:
有幾個實作上面結構的方法,可以在第一次需要實例時再建立物件,也就是採用所謂的Lazy Initialization:
public class Singleton {
private static Singleton instance = null;
private Singleton() {
// ....
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
// .. 其它實作
}
上面的實作適用於單執行緒的程式,在多執行緒的程式下,以下的寫法在多個執行緒的競爭資源下,將仍有可能產生兩個以上的實例,例如下面的情況:
Thread1: if(instance == null) // true
Thread2: if(instance == null) // true
Thread1: instance = new Singleton(); // 產生一個實例
Thread2: instance = new Singleton(); // 又產生一個實例
Thread1: return instance; // 回傳一個實例
Thread2: return instance; // 又回傳一個實例
在多執行緒的環境下,為了避免資源同時競爭而導致如上產生多個實例的情況,加上同步(synchronized)機制:
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
synchronized static public Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
不過這種簡單的寫法不適合用於像伺服器這種服務很多執行緒的程式上,同步機制會造成相當的效能低落,為了顧及Singleton、Lazy Initialization與效能問題,因而有了Double-check Locking的模式:
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance() {
if (instance == null){
synchronized(Singleton.class){
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
Java中Runtime類別的作法就簡單多了,它捨棄了Lazy Initialization,如果您的實例初始化不是很久的話,可以用這種方式:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
// ....
}
public static Singleton getInstance() {
return instance;
}
// 其它實作
}
Singleton本身的觀念簡單但套用很廣,因而很多時候必須對實際環境作一些考量與調整,建議您也看看有關於Singleton的這篇
相關詞條
-
singleton模式
ection ection getPrin
-
單件模式
gleton gleton gleton
設計模式-單件模式(singleton) Singleton模式的實現 -
設計模式
設計模式(Design pattern)是一套被反覆使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了可重用代碼、讓代碼更容易被...
簡介 設計框架 設計原則 基本模式 設計步驟 -
單態模式
單態定義:Singleton模式主要作用是保證在Java應用程式中,一個類Class只有一個實例存在。
簡介 使用原理 -
設計模式與遊戲完美開發
《設計模式與遊戲完美開發》是於2017年1月清華大學出版社出版的一本圖書,作者是蔡升達
前言 圖書簡介 目錄 -
單例模式
單例模式是一種常用的軟體設計模式。在它的核心結構中只包含一個被稱為單例類的特殊類。通過單例模式可以保證系統中一個類只有一個實例而且該實例易於外界訪問,從...
單例模式 簡介 動機 單例模式的要點 實例 -
圖解設計模式
《圖解設計模式》是一部由[日] 結城浩所著書籍,人民郵電出版社出版發行。
出版信息 內容簡介 結城浩 目錄 叢書信息 -
設計模式[設計模式概念]
設計模式(Design Pattern)是一套被反覆使用、多數人知曉的、經過分類的、代碼設計經驗的總結。 使用設計模式的目的:為了代碼可重用性、讓代碼更...
簡介 設計框架 設計原則 基本模式 設計步驟 -
軟體設計模式
軟體設計模式(Design pattern),又稱設計模式,是一套被反覆使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了可重用...
簡介 歷史 模式格式 相近術語 模式原則