單例模式
此條目需要補充更多來源。 (2018年10月22日) |
單例模式(Singleton pattern),也叫單子模式,是一種常用的軟件設計模式[1],屬於創建型模式的一種。在應用這個模式時,單例對象的類必須保證只有一個實例存在。許多時候整個系統只需要擁有一個的全局對象,這樣有利於我們協調系統整體的行為。比如在某個服務器程序中,該服務器的配置信息存放在一個文件中,這些配置數據由一個單例對象統一讀取,然後服務進程中的其他對象再通過這個單例對象獲取這些配置信息。這種方式簡化了在複雜環境下的配置管理。
實現單例模式的思路是:一個類能返回對象一個引用(永遠是同一個)和一個獲得該實例的方法(必須是靜態方法,通常使用getInstance這個名稱);當我們調用這個方法時,如果類持有的引用不為空就返回這個引用,如果類保持的引用為空就創建該類的實例並將實例的引用賦予該類保持的引用;同時我們還將該類的構造函數定義為私有方法,這樣其他處的代碼就無法通過調用該類的構造函數來實例化該類的對象,只有通過該類提供的靜態方法來得到該類的唯一實例。
單例模式在多線程的應用場合下必須小心使用。如果當唯一實例尚未創建時,有兩個線程同時調用創建方法,那麼它們同時沒有檢測到唯一實例的存在,從而同時各自創建了一個實例,這樣就有兩個實例被構造出來,從而違反了單例模式中實例唯一的原則。 解決這個問題的辦法是為指示類是否已經實例化的變量提供一個互斥鎖(雖然這樣會降低效率)。
構建方式
[編輯]通常單例模式在Java語言中,有兩種構建方式:
- 懶漢方式。指全局的單例實例在第一次被使用時構建。
- 餓漢方式。指全局的單例實例在類裝載時構建。
例子
[編輯]Java
[編輯]在Java語言中,單例模式(餓漢模式)應用的例子如下述代碼所示:
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
// Private constructor suppresses
// default public constructor
private Singleton() {};
public static Singleton getInstance() {
return INSTANCE;
}
}
在Java編程語言中,單例模式(懶漢模式)應用的例子如下述代碼所示 (此種方法只能用在JDK5及以後版本(注意 INSTANCE 被聲明為 volatile),之前的版本使用「雙重檢查鎖」會發生非預期行為[2]):
public class Singleton {
private static volatile Singleton INSTANCE = null;
// Private constructor suppresses
// default public constructor
private Singleton() {};
//Thread safe and performance promote
public static Singleton getInstance() {
if(INSTANCE == null){
synchronized(Singleton.class){
// When more than two threads run into the first null check same time,
// to avoid instanced more than one time, it needs to be checked again.
if(INSTANCE == null){
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
C++
[編輯]在C++編程語言中,單例模式應用的例子如下述代碼所示(這裡僅僅提供一個示例;由於加入了鎖,這代碼是線程安全的):
// ...
class lock
{
public:
lock();
lock(lock const & l);
~lock();
lock & operator =(lock const & l);
void request();
void release();
// ...
};
lock::lock()
{
// ...
}
// ...
lock::~lock()
{
// ...
}
// ...
void lock::request()
{
// ...
}
void lock::release()
{
// ...
}
// ...
// assumes _DATA_TYPE_ has a default constructor
template<typename _DATA_TYPE_>
class singleton
{
public:
static _DATA_TYPE_ * request();
static void release();
private:
singleton();
singleton(singleton<_DATA_TYPE_> const & s);
~singleton();
singleton<_DATA_TYPE_> & operator =(singleton<_DATA_TYPE_> const & s);
static _DATA_TYPE_ * pointer;
static lock mutex;
// ...
};
template<typename _DATA_TYPE_>
_DATA_TYPE_ * singleton<_DATA_TYPE_>::pointer = nullptr;
template<typename _DATA_TYPE_>
lock singleton<_DATA_TYPE_>::mutex;
template<typename _DATA_TYPE_>
_DATA_TYPE_ * singleton<_DATA_TYPE_>::request()
{
if(singleton<_DATA_TYPE_>::pointer == nullptr)
{
singleton<_DATA_TYPE_>::mutex.request();
if(singleton<_DATA_TYPE_>::pointer == nullptr)
{
singleton<_DATA_TYPE_>::pointer = new _DATA_TYPE_;
}
singleton<_DATA_TYPE_>::mutex.release();
}
return singleton<_DATA_TYPE_>::pointer;
}
template<typename _DATA_TYPE_>
void singleton<_DATA_TYPE_>::release()
{
if(singleton<_DATA_TYPE_>::pointer != nullptr)
{
singleton<_DATA_TYPE_>::mutex.request();
if(singleton<_DATA_TYPE_>::pointer != nullptr)
{
delete singleton<_DATA_TYPE_>::pointer;
singleton<_DATA_TYPE_>::pointer = nullptr;
}
singleton<_DATA_TYPE_>::mutex.release();
}
}
template<typename _DATA_TYPE_>
singleton<_DATA_TYPE_>::singleton()
{
// ...
}
// ...
int main()
{
int * s;
s = singleton<int>::request();
// ...
singleton<int>::release();
return 0;
}
GO
[編輯]GO語言中的單例模式:
var _instance *service
var once sync.Once
type service struct {
Name string
}
func Service() *service {
once.Do(func() {
_instance = &service{}
})
return _instance
}
func (this *service) Startup() {
}
func (this *service) Stop() {
}
func (this *service) Restart() {
}
Objective-C
[編輯]OC語言中的單例模式:
@interface Control : NSObject
+(id)getShare;
@end
static Control *mControl;
@implementation Control
+(id)getShare
{
if (mControl == nil) {
mControl = [[Control alloc] init];
}
return mControl;
}
-(id)init {
//你需要初始化的属性。。。
}
@end
PHP
[編輯]PHP語言中的單例模式:
<?php
class singleton
{
private function __construct()
{
}
static public function instance()
{
static $obj = null;
if($obj === null)
{
$obj = new self();
}
return $obj;
}
}
?>
參考文獻
[編輯]- ^ Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison Wesley. 1994: 127ff. ISBN 0-201-63361-2.
- ^ David Bacon,Joshua Bloch etc. The "Double-Checked Locking is Broken" Declaration. [2012-08-17]. (原始內容存檔於2012-03-01) (英語).
外部連結
[編輯]- A Q&A page (java.sun.com)
- Java單例對象同步問題探討 (頁面存檔備份,存於網際網路檔案館)
參見
[編輯]