zoukankan      html  css  js  c++  java
  • 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

    个人学习笔记,欢迎拍砖!---by hellogiser

    Author: hellogiser
    Warning: 本文版权归作者和博客园共有,欢迎转载,但请保留此段声明,且在文章页面明显位置给出原文连接。Thanks!
    Me: 如果觉得本文对你有帮助的话,那么【推荐】给大家吧,希望今后能够为大家带来更好的技术文章!敬请【关注】
  • 相关阅读:
    C 语言 字符串命令 strstr()的用法 实现将原字符串以分割串分割输出
    C# 中对 IEnumerable IEnumerator yield 的理解
    C 语言 用字符输出菱形图案的函数(可自定义边长及字符样式)
    C 语言 对角线添充二维数组
    C 语言 边读 边写入文件
    [转]Page.RegisterRequiresRaiseEvent()与Page.RegisterRequiresPostBack()
    asp.net 判断是手机或电脑访问网页的方式
    表达式树【转】
    ADO.NET中的“返回多个结果集”和“MARS”【转】
    SQL2005转2000的方法【转】
  • 原文地址:https://www.cnblogs.com/hellogiser/p/3742067.html
Copyright © 2011-2022 走看看