作用:保证一个类只能有一个实例。并提供一个访问它的全局访问点。属于创建型模式。
实现要点:一.使用一个静态成员变量作为“全局”实例,这样就确保了唯一性
二.使用静态的成员函数instance()替代new来获取该类的实例,这样就提供了全局的访问点
三.构造函数设为private,使调用者不能用new来创建此类的实例
代码:两种方法实现单件模式,一种是Early initialization,一种是Lazy Initialization。
方法一:
//
Early initialization
class
EarlySingleton
{
private
static
EarlySingleton earlyInstance
=
new
EarlySingleton();
private
EarlySingleton()
{
}
public
static
EarlySingleton Instance()
{
return
earlyInstance;
}
}
方法二:
//
Lazy Initialization
class
LazySingleton
{
private
static
LazySingleton lazyInstance;
private
LazySingleton()
{
}
public
static
LazySingleton Instance()
{
if
(lazyInstance
==
null
)
{
lazyInstance
=
new
LazySingleton();
}
return
lazyInstance;
}
}
深入:观察代码可以看出,方法二的静态变量只有在需要使用的时候才实例化,与方法一不管什么时候都一直存在相比,更加节省系统资源。但是方法二也不是没有问题——当使用多线程时,由于可能的线程异步,某个线程已经开始实例化lazyInstance但还未完成,而另一个线程在判断lazyInstance == null时仍然为true,从而又实例化一个,这将招致严重的错误。解决方法有三个:这三个方法是:
1、使用 [MethodImpl(MethodImplOptions.Synchronized)] ,指定instance()方法同时只能被一个线程使用
2、lock(myObject),是对一个对象加互斥锁,只允许一个线程访问其后大括号中语句块,直到该语句块的代码执行完才解锁,解锁后才允许其他的线程执行其语句块。
3、使用 Mutex 类的 WaitOne 方法。
按这三个方法修改后的代码分别如下:
1.
using
System.Threading;
using
System.Runtime.CompilerServices;
//
Lazy Initialization
class
LazySingleton
{
private
static
LazySingleton lazyInstance;
private
LazySingleton()
{
}
[MethodImpl(MethodImplOptions.Synchronized)]
//
方法的同步属性
public
static
LazySingleton Instance()
{
if
(lazyInstance
==
null
)
{
lazyInstance
=
new
LazySingleton();
}
return
lazyInstance;
}
}
2.
using
System.Threading;
//
Lazy Initialization
class
LazySingleton
{
private
static
LazySingleton lazyInstance;
static
object
myObject
=
new
object
();
private
LazySingleton()
{
}
public
static
LazySingleton Instance()
{
lock
(myObject)
{
if
(lazyInstance
==
null
)
{
lazyInstance
=
new
LazySingleton();
}
return
lazyInstance;
}
}
}
3.
using
System.Threading;
//
Lazy Initialization
class
LazySingleton
{
private
static
LazySingleton lazyInstance;
static
object
myObject
=
new
object
();
private
static
Mutex mut
=
new
Mutex();
private
LazySingleton()
{
}
public
static
LazySingleton Instance()
{
mut.WaitOne();
if
(lazyInstance
==
null
)
{
lazyInstance
=
new
LazySingleton();
}
mut.ReleaseMutex();
return
lazyInstance;
}
}
发现很多设计模式的作者都是写到此为止。其实还未结束,James.W.Cooper在他的书里指出:当唯一的实例已经存在时,最好给调用者抛出一个明确的异常信息。这个很有道理,如果单件实例已存在,而调用者不知道,我们不吭声就把这个已存在的单件实例返回给他,很有可能导致他犯更大的错误。
修改Instance()中代码:
if
(lazyInstance
==
null
)
{
lazyInstance
=
new
LazySingleton();
}
else
{
throw
new
Exception(
"
Singleton should be init just once
"
);
}