45. Singleton类的C++/C#实现[Singleton]

【题目】

设计一个类,我们只能生成该类的一个实例。

【分析】

单例模式的意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点。让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可、以被创建(通过截取创建新对象的请求),并且它可以提供一个访问该实例的方法。这就是Singleton模式。

应用场景包括常见的任务管理器、回收站、程序的日志应用、数据库的连接池、操作系统的文件系统、多线程的线程池等等。总体来说单件模式主要用在资源共享的情况下,避免由于各种资源操作导致的性能损耗和资源控制的情况下互相通信,比如线程池。

由于设计模式在面向对象程序设计中起着举足轻重的作用,在面试过程中很多公司都喜欢问一些与设计模式相关的问题。在常用的模式中,Singleton是唯一一个能够用短短几十行代码完整实现的模式。因此,写一个Singleton的类型是一个很常见的面试题。

【解法1】

(1)不好的解法一:只适用于单线程环境

由于要求只能生成一个实例,因此要把构造函数设为私有函数以禁止他人创建实例。我们可以定义一个静态的实例,在需要的时候创建该实例。

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 

public  sealed  class  Singleton1
{
    
private  Singleton1()
    {
    }

    
private   static  Singleton1 instance = null;
    
public   static  Singleton1 Instance
    {
        get
        {
            
if  (instance == null)
                instance = 
new  Singleton1();

            
return  instance;
        }
    }
}

【解法2】

(2)不好的解法二:能适应多线程,但效率低

上述Singleton在单线程下能正常工作,但在多线程的情况下就有问题。为了保证在多线程环境下使用,我们需要加上一个同步锁。

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 

public  sealed  class  Singleton2
{
    
private  Singleton2()
    {
    }

    
private   static  readonly object syncObj =  new  object();

    
private   static  Singleton2 instance = null;
    
public   static  Singleton2 Instance
    {
        get
        {
            lock (syncObj)
            {
                
if  (instance == null)
                    instance = 
new  Singleton2();
            }

            
return  instance;
        }
    }
}

上述代码保证了在多线程环境下也只能得到一个实例。但是,Singleton2还不是很完美,每次通过属性Instance得到的Singleton2的实例,都会试图加上一个同步锁,这是一个耗时的操作。

【解法3】

(3)可行的解法:加上同步锁前面两次判断实例是否存在(Dobule-Check)

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 

public  sealed  class  Singleton3
{
    
private  Singleton3()
    {
    }

    
private   static  object syncObj =  new  object();

    
private   static  Singleton3 instance = null;
    
public   static  Singleton3 Instance
    {
        get
        {
            
if  (instance == null)
            {
                lock (syncObj)
                {
                    
if  (instance == null)
                        instance = 
new  Singleton3();
                }
            }

            
return  instance;
        }
    }
}

【解法4】

(4)强烈推荐的解法一:利用静态构造函数

C#的语法中有一个函数能够确保只用一次,那就是静态构造函数,我们可以利用这个特性实现Singleton模式。

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 

public  sealed  class  Singleton4
{
    
private  Singleton4 ()
    {
    }

    
private   static  Singleton4 instance =  new  Singleton4 ();
    
public   static  Singleton4 Instance
    {
        get
        {
            
return  instance;
        }
    }
}

C#是在调用静态构造函数时初始化静态变量,这样我们就保证只初始化一次instance。但C#中调用静态构造函数是不确定的,而是当.Net运行时发现第一次使用一个类型的时候自动调用该类型的静态构造函数,即第一次用到Singleton4的时候,就会过早地创建实例,降低内存使用效率。

【解法5】

(5)强烈推荐的解法二:实现按需创建实例

Singleton5很好地解决了Singleton4中的实例创建过早的问题。

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 

public  sealed  class  Singleton5
{

    
private  Singleton5()
    {
    }

    
public   static  Singleton5 Instance
    {
        get
        {
            
return  Nested.instance;
        }
    }

    
// nested class
     private   class  Nested
    {
        
static  Nested()
        {
        }

        internal 
static  readonly Singleton5 instance =  new  Singleton5();
    }
}

在内存定义一个私有类型,嵌套类,当第一次用到这个嵌套类型的时候,就会调用静态构造函数创建singleton5的实例instance。类型nested只在属性singleton5.instance中用到,由于其私有属性他人无法使用nested类型。因此当我们第一次试图通过属性singleton5.instance得到singleton5的实例时,会自动调用nested的静态构造函数创建实例instance。如果我们不调用属性singleton5.instance,那么就不会触发.NET运行时调用nested,也不会创建实例,这样就真正做到了按需创建。

【参考】

http://zhedahht.blog.163.com/blog/static/2541117420105146828433/

http://www.cppblog.com/dyj057/archive/2005/09/20/346.html

http://www.cnblogs.com/cxjchen/p/3148582.html

http://www.cnblogs.com/panweishadow/archive/2014/04/13.html

http://en.wikipedia.org/wiki/Double-checked_locking

转载于:https://www.cnblogs.com/hellogiser/p/3742067.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值