[设计模式] Singleton Pattern

  前些天有人面试碰到了这个东东,可能下次我换工作时说不定也会碰到,这个东东可是人见人爱,有讲设计模式肯定会被问到的一个模式。所以也就顺便看看,写写,这篇文章的主要来源是老外写的《Implementing the Singleton Pattern in C#》,半译半写就是这样。没有什么特别的,不过不知道国内有没有人翻译过此文,不管3721咱开始吧。

  由于我没有系统的学过设计模式,也没有人教我所以碰到了就顺便看一看的,在讲Singleton设计模式之前当然我们要知道什么时候才使用到这个模式,什么时候我们最好不要用这个设计模式,不然学这个有什么用呢?不知道大家是怎么想的,下面我们来看看到底什么时候我们才使用Singleton模式,使用该模式的必要条件就是在一个系统中一个类有且只有一个实例;相反就不能使用Singleton模式。但要注意的是我们不要用Singleton模式来存取全局变量,这违背了Singleton模式的用意;同时我们也不要用Singleton模式来做数据库的联接,这样会浪费太多的资源,因为不能及时的释放资源。

  从上面我们可以知道Singleton模式的特点:一个Singleton模式类要通过自己来实例化自己,并且不能在其它地方被实例化,所以必需要有一个没有带参数的Private构造(确保不能用new来实例化)和带sealed的类(确保不能被继承);需要一个静态方法得到自身类的实例对象。下面我们来看看在C#中实现Singleton模式的几种方法,在后面回加以说明(注:例子来自《Implementing the Singleton Pattern in C#)

// Bad code! Do not use!
public sealed class Singleton
{
    static Singleton instance=null;
 
    Singleton()
    {
    }
 
    public static Singleton Instance
    {
        get
        {
            if (instance==null)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }

}

  以上是实现Singleton模式的第一种方法,这种方法不是线程安全的,也就是说在两个不同的线程中有可能在同一时间创建对象,即创建了两个不同的实例对象,这就违背了Singleton模式,因此这种方法是不提倡的。

public sealed class Singleton
{
    static Singleton instance=null;
    static readonly object padlock = new object();
 
    Singleton()
    {
    }
 
    public static Singleton Instance
    {
        get
        {
            lock (padlock)
            {
                if (instance==null)
                {
                    instance = new Singleton();
                }
                return instance;
            }
        }
    }

}

  这种方法是线程安全的,通过锁定一个共享对象,因为在创建对象时先锁定了一个对象。例如在两个类中都调用了这个Instance属性,当第一个调用时先将padlock对象锁定了,则第二个调用类就只能等到这个对象解锁以后才能进行。然后再判断是否已经创建了这个对象,如果没有创建则创建此对象。虽然在线程上是安全的,但是每次调用时都会有一个锁定的过程这样就会消耗一定的资源,也就是说性能上有点问题!

// Bad code! Do not use!
public sealed class Singleton
{
    static Singleton instance=null;
    static readonly object padlock = new object();
 
    Singleton()
    {
    }
 
    public static Singleton Instance
    {
        get
        {
            if (instance==null)
            {
                lock (padlock)
                {
                    if (instance==null)
                    {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }
}

  以上例子似乎是线程安全的,但是它在JAVA.NET下都会出现问题,由于我对JAVA不熟悉所以英文当然就看的比较模糊,应该是说内存边界(memory barrier我也不知道对不对)会出现问题;在.NET中这种做法无法实现延迟初始化,总之这种做法是不推荐的。(等我知道怎么回事了再补上吧!或是哪位能给予指导,谢谢!)

public sealed class Singleton

{

    static readonly Singleton instance=new Singleton();

 

    // Explicit static constructor to tell C# compiler

    // not to mark type as beforefieldinit

    static Singleton()

    {

    }

 

    Singleton()

    {

    }

 

    public static Singleton Instance

    {

        get

        {

            return instance;

        }

    }

}

  通过静态构造来实现Sigleton设计模式,在大多数情况下我们都会采用这种来实现Sigleton设计模式。在C#中静态构造函数只会在一个对象被初始化或一个静态成员被引用时执行,并且在整个程序域中只执行一次。变量标记为 readonly,这意味着只能在静态初始化期间,该变量的值就是固定不变的了,所以也就不可能再初始化对象了。也就是说不初始化了一次,也就是Sigleton设计模式,并且保证线程安全。

public sealed class Singleton
{
    Singleton()
    {
    }
 
    public static Singleton Instance
    {
        get
        {
            return Nested.instance;
        }
    }
    
    class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested()
        {
        }
 
        internal static readonly Singleton instance = new Singleton();
    }
}

  这种做法实现了延迟实例化,因此这也是一种不错的选择。基本上Sigleton设计模式就这5种实现方法,而最值的推荐的是第4种方法,代码简单而又不失性能。

原文地址:https://www.cnblogs.com/xdotnet/p/pattern_sigleton.html