C#设计模式之单例模式

    最近常常会看一些设计模式上书籍,对设计模式有了必定的了解,特此作一下笔记,也给博友们提供一些帮助。数据库

1.什么是单例模式?设计模式

     网上有不少文章都有详情的描述,大体意思上能够理解为一个类只有一个实例,也就是保证一个类只有一种实例的实现方法,官方上是这样定义的:确保一个类只有一个实例,并提供一个全局访问点。多线程

通俗易懂就是:每次去实例化一个对象都是同一个,指向的都是同一个内存地址。并发

2.为何要使用单例模式,单例模式的好处在哪?性能

      每一种设计模式均可以解决开发中遇到的一些问题,好比说提升性能,解耦合,可扩展,功能更加灵活等等。测试

      现实中的应用场景: 咱们平常使用的电脑上都有一个回收站,在整个操做系统中,回收站只能有一个实例,整个系统都使用这个惟一的实例,并且回收站自行提供本身的实例。所以回收站是单例模式的应用。平常开发中遇到与数据库创建链接,若是每次都是建立新对象去创建链接,速度回很慢,因此设计成单例模式,提升访问速度。优化

3.单例模式在C#中的具体实现。this

    确保一个类只有一个实例,并提供一个全局访问点。咱们依照这个思路进行实现。spa

    本次单例实现总共用了三种方式进行简单实现:操作系统

    方式一:

    

 /// <summary>
    /// 单例模式的简单实现
    /// </summary>
    public class Singleton
    {
        /// <summary>
        /// 建立全局静态变量
        /// </summary>
        private static Singleton _singleton = null;
        /// <summary>
        /// 私有化默认构造器,为何要私有化默认构造器,若是不私有,那么能够经过new Singleton()进行实例化对象了,就达不到预想效果。
        /// </summary>
        private Singleton()
        {

        }
        /// <summary>
        /// 提供一个建立实例的方法
        /// </summary>
        /// <returns></returns>
        public static Singleton CreatInstance()
        {
            //判断,若是对象没有建立,那么进行建立。有建立,不在重复建立
            if (_singleton == null)
            {
                _singleton=new Singleton();
            }
            return _singleton;
        }
    }

 

  测试结果以下:

     看测试结果确实达到了咱们预想的要求。单例的效果已经达到了,可是并非很完美,当前只在单线程上是知足了,若是多线程下又是怎么样的呢?接下来就用一个简单的例子测试一下多线程的使用的状况下。代码实现以下:

 //多线程模拟,十个线程同时访问
            for (int i = 0; i < 10; i++)
            {
                new Action(() =>
                {
                    Thread.Sleep(1000);
                    Singleton singleton = Singleton.CreatInstance();
                    singleton.Show(); //在Singleton类里面添加一个无参的Show方法

                }).BeginInvoke(null, null);
            }

  

   

  如上图发现,当十个线程同时访问时,建立了多个对象的实例,并没达到单例模式的效果。为何会这样?缘由是这样的,当第一个线程进入后,

            //判断,若是对象没有建立,那么进行建立。有建立,不在重复建立
            if (_singleton == null)
            {
                _singleton=new Singleton();
            }

 会去判断这个对象是否已经被实例化,由于程序执行速度是很快的,当第一个线程发现对象未实例化时,第一个线程开始对对象进行实例化,第一个线程还未实例化完成第二个线程就已经进来了,开始对对象进行判断,开始实例化。最终形成如上效果。

    针对如上状况,怎么解决呢?有人就会想到,加把锁锁起来就好了。这种想法很是正确。咱们看看加锁后实现的方式。

 

 public class Singleton
    {
        /// <summary>
        /// 建立全局静态变量
        /// </summary>
        private static Singleton _singleton = null;
        private static object singleton_lock=new object();
        /// <summary>
        /// 私有化默认构造器
        /// </summary>
        private Singleton()
        {
            Console.WriteLine("建立了Singleton对象的实例");
        }
        /// <summary>
        /// 提供一个建立实例的方法
        /// </summary>
        /// <returns></returns>
        public static Singleton CreatInstance()
        {
            lock (singleton_lock)
            {
                //判断,若是对象没有建立,那么进行建立。有建立,再也不重复建立
                if (_singleton == null)
                {
                    _singleton = new Singleton();
                }
            }
            return _singleton;
        }
        public void Show()
        {
            Console.WriteLine($"执行Show方法:{this.GetType()}");
        }
    }

  运行后以下图:

多线程同时访问的状况下的问题就已经解决了。固然还能够再次优化一下,为了看到效果,对代码进行以下改造

改造以后再次执行

如上图发现,每个线程都进入lock里面,若是第一个线程进入lock实例化了对象,那么第二个就能够没有必要进入lock,咱们能够在线程进入lock前进行判断,最终代码改造以下,

 /// <summary>
    /// 单例模式的简单实现
    /// </summary>
    public class Singleton
    {
        /// <summary>
        /// 建立全局静态变量
        /// </summary>
        private static Singleton _singleton = null;
        private static object singleton_lock=new object();
        /// <summary>
        /// 私有化默认构造器
        /// </summary>
        private Singleton()
        {
            Console.WriteLine("建立了Singleton对象的实例");
        }
        /// <summary>
        /// 提供一个建立实例的方法
        /// </summary>
        /// <returns></returns>
        public static Singleton CreatInstance()
        {
            if (_singleton == null)
            {
                lock (singleton_lock)
                {
                    Console.WriteLine("开始进入lock...");
                    //判断,若是对象没有建立,那么进行建立。有建立,不在重复建立
                    if (_singleton == null)
                    {
                        _singleton = new Singleton();
                    }
                }
            }
            return _singleton;
        }
        public void Show()
        {
            Console.WriteLine($"执行Show方法:{this.GetType()}");
        }
    }

  执行效果以下

图中发现线程进入lock的次数少了,线程并发少可能做用不大,若是是并发量达到百万次甚至更多,那么效率会有明显提高。双if加lock是最标准的实现单例模式的写法。

接下来介绍两种比较简便的单例模式的实现,效果和上面的同样。

方式2、

 public class SingletonSecond
    {
        private static SingletonSecond _singletonSecond = new SingletonSecond();
        private SingletonSecond()
        {
            Console.WriteLine("建立了该对象的实例");
        }

        public static SingletonSecond CreatInstance()
        {
            return _singletonSecond;
        }
        public void Show()
        {
            Console.WriteLine($"执行Show方法:{this.GetType()}");
        }
    }

  

方式3、

 public class SingletonThrird
    {
        private static SingletonThrird _singletonThrid = null;
        private SingletonThrird()
        {
            Console.WriteLine("建立了该对象的实例");
        }
        static SingletonThrird()
        {
            _singletonThrid=new SingletonThrird();
        }
        public static SingletonThrird CreatInstance()
        {
            return _singletonThrid;
        }
        public void Show()
        {
            Console.WriteLine($"执行Show方法:{this.GetType()}");
        }
    }

  

以上就单例模式的实现方式。提供参考,职场小白欢迎指正!

相关文章
相关标签/搜索