zoukankan      html  css  js  c++  java
  • C#设计模式之单例模式

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

    1.什么是单例模式?

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

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

    2.为什么要使用单例模式,单例模式的好处在哪?

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

          现实中的应用场景: 我们日常使用的电脑上都有一个回收站,在整个操作系统中,回收站只能有一个实例,整个系统都使用这个唯一的实例,而且回收站自行提供自己的实例。因此回收站是单例模式的应用。日常开发中遇到与数据库建立连接,如果每次都是创建新对象去建立连接,速度回很慢,所以设计成单例模式,提高访问速度。

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

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

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

        方式一:

        

     /// <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是最标准的实现单例模式的写法。

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

    方式二、

     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()}");
            }
        }
    

      

    方式三、

     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()}");
            }
        }
    

      

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

  • 相关阅读:
    MyBatis的动态SQL语句这么厉害的!
    连接数据库,使用c3p0技术连接MySQL数据库
    Servlet 常见的乱码解决方案
    超级签具体实现
    Xcode报错You don’t have permission.
    SpringBoot+Mybatis整合实例
    恢复mysql数据库误删数据
    日期(date)运用座谈会
    程序猿日记--学习怎样学习
    服务器数据库密码忘记
  • 原文地址:https://www.cnblogs.com/jiangxifanzhouyudu/p/10264956.html
Copyright © 2011-2022 走看看