设计模式-Singleton

需求:需要一个类,这个类只能有一个实例。

首先看一个很简单的例子

Code
 1public class Singleton
 2{
 3    private static Singleton instance;
 4
 5    private Singleton() { }
 6
 7    public Singleton Instance
 8    {
 9        get
10        {
11            if (instance == null)
12            {
13                instance = new Singleton();
14            }

15
16            return instance;
17        }

18    }

19}

 

这个例子是在简单不过的了.这里用了一个属性,其实改用方法也一样,如下

   

Code
 1public class Singleton
 2    {
 3        private static Singleton instance;
 4
 5        private Singleton() { }
 6
 7        public Singleton GetInstance()
 8        {
 9            if (instance == null)
10            {
11                instance = new Singleton();
12            }

13
14            return instance;
15        }

16    }

17
18

注意,这里用了一个技巧,或者也可以称做一种模式.那就是Lazy-Allocate(缓分配),或者Lazy-Load.
if(instance == null)
{
    instance = new Singleton();
}
.NET Framework中大量的使用了这种方法,Lazy-Allocate的设计概念很简单,就是未使用前不预付成本。


但是这种方式在单线程下确实运行的很好.一旦到了多线程就可能出现多个实例


需求:多线程环境下的单例

 

 

Code
    public class Singleton
    {
        
// volatile 实例的指令不被编译器重新调整 
        private static volatile Singleton instance;

        
private static object lockHelper = new object();

        
private Singleton() { }

        
public Singleton Instance
        {
            
get
            {
                
// double check
                if (instance == null)
                {
                    
lock (lockHelper)
                    {
                        
if (instance == null)
                            instance 
= new Singleton();
                    }
                }

                
return instance;
            }
        }
    }


首先多线程下判断instance为null的时候才可以进行实例,而实例化的时候要加一个锁
这里lockHelper,可以是你自己的有用的代码,也可以是一个仅仅起标识作用的不参与运算的对象
然后在判断是否实例化.这个方法也叫Double Check.

大家注意到private static volatile Singleton instance;多了一个关键字 volatile,这个是什么用的呢
就是在编译的时候,不要让Runtime调整编译指令的顺序

因为DotNet在编译的时候会对指令进行优化调整.所以即便用了Double Check还是有很小的机会创建多个Singleton的实例

所以我们加上volatile关键字,让Runtime不对这个instance做指令调整.这样就完全实现了多线程的Singleton.

有没有更简洁一点的用法呢.

看下面的例子

 

Code
 1    public class Singleton
 2    {
 3        private static readonly Singleton instance = new Singleton();
 4
 5        private Singleton() { }
 6
 7        public Singleton Instance
 8        {
 9            get
10            {
11                return instance;
12            }

13        }

14    }

15
16

这样就可以实现在多线程环境下的Singleton模式.为什么?

回忆一下readonly的用法,他本身就是只能进行一次初始化,然后就和const没什么区别.

那么还有一个问题.如果我的构造函数是有参数的时候该怎么办呢.

 

 

Code
    public class Singleton
    {
        
private static readonly Singleton instance = new Singleton();

        
private Singleton() { }

        
public Singleton Instance
        {
            
get
            {
                
return instance;
            }
        }

        
public int X { getset; }
    }

这样本来需要在构造函数中需要的参数,我们把它改成一个属性.让这个属性是可以修改的..

噢,还可以考虑的解决方案.但是问题还是有.

比如有时候一些参数是有依赖性的.最好放在构造函数执行该怎么办呢.

看下面的代码

 

 

Code
    public class Singleton
    {
        
private static readonly Singleton instance = new Singleton();

        
private static bool instanced = false;

        
private static object lockHelper = new object();

        
private Singleton() { }

        
public Singleton Instance
        {
            
get
            {
                
if (instanced)
                    
return instance;
                
else
                    
throw new Exception("");
            }
        }

        
public int X { getset; }

        
public void Init(int x)
        {
            
if (!instanced)
            {
                
lock (lockHelper)
                {
                    
if (!instanced)
                    {
                        
this.X = x;

                        instanced 
= true;
                    }
                }
            }
        }
    }


首先在私有构造函数中,我们把要执行的code转移到Init方法中,让私有构造函数是空.
这样我们保证了它是一个Singleton

其次必须使用Init来初始化这个对象.如果没有初始化就引用,这个时候抛出异常.

第三.Init方法也只执行一次.

这样一个保证多线程环境下,任意参数的构造的一个Singleton模式就完成了.

当然设计模式就是一种思想,不能生搬硬套.具体环境具体操作.


在单例模式的使用中,要注意一下几个方面:

Singleton模式中的构造器也可以设置为protected允许子类派生
Singleton模式一般不要支持ICloneable接口,避免导致多个对象实例
Singleton模式一般不要支持序列化,因为这也有可能导致多个对象实例
小心应对多线程环境;

Singleton的关键是只能生成一个实例,在推敲一下,就是只能生成固定数量的实例,那么这种情况下,Singleton就是一个特例.

关于生成固定数量的实例,有兴趣的朋友可以自行研究一下.

转载于:https://www.cnblogs.com/plutowang/archive/2009/04/16/1437438.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值