大话设计之单例模式

      单例模式:提倡一个类只有一个实例,提供一个访问它的全局访问点。通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且可以提供一个访问该实例的方法。

      单例模式除了保证唯一实例外,还有单例模式因为SIngleton类封装它的唯一实例,这样它可以严格地控制客户怎样访问它以及何时访问它。简单来讲就是对唯一实例的受控访问。与.Net框架中的Math类有相似之处。

  机构图如下:

  

     来看看单例模式的基本代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace 单例模式基本模型
{
    class Program
    {
        //客户端
        static void Main(string[] args)
        {
            Singleton Instance1 = Singleton.GetInstance();
            Singleton Instance2 = Singleton.GetInstance();

            if (Instance1 == Instance2)
            {
                Console.WriteLine("两个实例是一模一样的实例。");
            }

        }
    }
    class Singleton
    {
        private static Singleton instance;

        //构造方法采用private,外界便无法用new创建该类的实例
        private Singleton()
        { }

        //该方法提供一个获得该类实例的全局访问点,是唯一的
        public static Singleton GetInstance()
        {
            //如果实例不存在,则返回一个新实例,否则返回原实例。
            if (instance == null)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }
}
      上面代码在多线程的程序中,注意是同事访问Singleton类,调用GetInstance()方法,会有可能造成创建多个实例。

     改进版代码:

class Singleton
    {
        private static Singleton instance=null;
        //创建一个静态只读的进程辅助对象
        private static readonly object ProgressLock = new object();

        //构造方法采用private,外界便无法用new创建该类的实例
        private Singleton()
        { }

        //该方法提供一个获得该类实例的全局访问点,是唯一的
        public static Singleton GetInstance()
        {
            lock (ProgressLock)
            {
                
                if (instance == null)
                {
                    instance = new Singleton();
                }
            }
           
            return instance;
        }
    }
     lock是确保当一个线程位于代码的临界区时,另一个线程不进去临界区,如果其他线程试图进入锁定的代码,则它将一直等待,直到该对象被释放。

    但是这段代码在每次调用GetInstance方法时都需要lock,所以还有改进版的代码:

    双重锁定:

class Singleton
    {
        private static Singleton instance=null;
        //创建一个静态只读的进程辅助对象
        private static readonly object ProgressLock = new object();

        //构造方法采用private,外界便无法用new创建该类的实例
        private Singleton()
        { }

        //该方法提供一个获得该类实例的全局访问点,是唯一的
        public static Singleton GetInstance()
        {
            if (instance == null)
            {
                lock (ProgressLock)
                {

                    if (instance == null)
                    {
                        instance = new Singleton();
                    }
                }
            }
                 
            return instance;
        }
    }
   其实在实际应用当中,C#与公共语言运行库也提供了一种静态初始化方法,这种方法不需要开发人员显式地编写安全代码,即可解决多线程环境下它是不安全的问题。

//sealed关键字防止派生
    public sealed class Singleton
    {
        //在第一次引用类的成员时创建实例,公共语言运行库负责处理变量的初始化
        private static readonly Singleton instance=new Singleton();
       
        //构造方法采用private,外界便无法用new创建该类的实例
        private Singleton()
        { }

        public static Singleton GetInstance()
        {
            return instance;
        }
    }
    这种方式是在自己被加载时就将自己实例化,成为饿汉式。
 
     变量标记为readonly,这意味着只能在静态初始化期间(此处显示的示例)或在类构造函数中分配变量。该类标记为 sealed 以阻止发生派生,而派生可能会增加实例
 
     优点:该实现与前面的示例类似,不同之处在于它依赖公共语言运行库来初始化变量。它仍然可以用来解决Singleton模式试图解决的两个基本问题:全局访问和实例化控制。
缺点:由于有.NetFramework 进行初始化,所以我们对实例化机制的控制权较少,没办法和其他实现一样实现延迟初始化。在上面三种形式中,您能够在实例化之前使用非默认的构造函数或执行其他任务。

     总结:单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。

原文地址:https://www.cnblogs.com/xzpblog/p/5117990.html