【设计模式】之 Singleton 模式

引子

假设现在要做一个“家庭管理系统”, 有个类名字叫做 “Wife”。
需要实例化“MyWife”,我就new一个出来;
    Wife MyWife = new Wife(); //嘻嘻,属性挺多,方法么?洗衣做饭等等都有,但好像工作状态很不稳定
    MyWife.Wash();
程序另外一处也需要"MyWife", 好办啊
    Wife MyWife = new Wife();
    MyWife.Cook();
嗯?这个老婆和上面的是不是一个呢?好像不能保证。现在咱们国家婚姻法规定了一夫一妻制度。所以老婆嘛,是只有一个的(多的那不叫老婆)。
所以,问题是,如何保证程序里,一个类(Wife)只有一个实例(MyWife), 并提供一个该实例的全局访问点?

模型图

【设计模式】之 Singleton 模式

单线程Singleton模式

使用statics约束构造函数,在公有属性中实现类的实例化。

Singleton pattern “structural example"

使用:
Singleton t1 = Singleton.Instance;
Singleton t2 = Singleton.Instance;
Console.WriteLine( Object.Equals( t1, t2 ) );
输出结果: true
说明只有一个实例。

 

上面的并不是线程安全的,两个线程同时访问到if(_instance==null),就可能最后出来两个实例。

简单Singleton在多线程下的失败
 

多线程Singleton模式

代码
class  SingletonMuli
{
   
private   static   volatile  SingletonMuli _instance;
  
private   static   object  lockHelper  =   new   object ();  
   
private  SingletonMuli(){}

   
public   static  SingletonMuli Instance
   {
            
get
            {                
                    
lock (lockHelper)
                    {
                        
if (_instance  ==   null )       
                        {
                             _instance 
=   new  SingletonMuli();
                        }
                    }
             }
             
return  _instance;
    }
}

 

volatile是什么意思?见volatile关键字
上面的实现,线程每个Instance 属性方法的调用中都出现独占锁定。

 
多线程Singleton模式优化:
使用DCL(Double-Check Locking)
使用DCL优化多线程Singleton模式

这样,线程不是每次都加锁,只有判断对象实例没有被创建时它才加锁。

.NET平台支持的Singleton模式

.NET平台下Singleton

内联初始化 的代码相当于:
public static readonly Singleton _instance;
static Singleton()
{
   _instance = new Singleton();
}
访问静态字段的时候,静态构造函数必先被执行。即,初始化放在静态构造器;前面的单线程、多线程,放在属性中初始化。
(beforefileInit,在编译好的singleton类的metadata中可看到),实现了Lazy-initialization
同时.readonly保证只有一个实例;对NET静态构造器,编译器保证了多线程下自动加锁。
所以,NET平台下的多线程Singleton模式:
uses a private constructor and a static readonly instance variable that is lazily initialized. Thread safety is guaranteed by the compiler. (dofactory)

参数化的Singleton模式
上面的方法的缺陷是 静态构造器必须是私有的、无参的;参数化的Singleton如何实现?
1. 单线程、多线程---属性改为方法 Singleton s1 = Singleton.GetInstance(100,200);
2. 静态初始化     ---增加属性,或增加Init()方法初始化资源。Singleton s1 = Singleton.Instance(); s1.Init();

Singleton模式实例 负载均衡模型

多服务器环境,为确保任务均衡,任务分配器随机(选择最简单的策略)挑选一台服务器提供服务。
只能有一个任务分配器实例(Singleton模式!)并且任务分配器知道每个服务器的状态。
Only a single instance (the singleton) of the class can be created because servers may dynamically come on- or off-line and every request must go throught the one object that has knowledge about the state of the (web) farm.

载均衡模型

可以看出虽然初始化没有参数,但是程序中仍然选择用GetInstance方法替代属性。
我个人认为这样可以做到概念清晰,值得提倡

用.NET优化上面的实例

 

另:关于.NET下Singleton模式,
吕震宇在文章http://zhenyulu.cnblogs.com/articles/37246.html里谈到:
“利用.NET Framework平台优势实现Singleton模式,也带来了一些问题,比如无法继承,实例在程序一运行就被初始化,无法实现延迟初始化等。
详细情况可以参考微软MSDN文章:《Exploring the Singleton Design Pattern》 ”
好像和dofactory那句话不一致,现在看来,应该是dofactory说的有问题,应该是无法实现延迟初始化。

能够实现延迟初始化的方法:

延迟初始化

 

你可能感兴趣的:(Singleton)