zoukankan      html  css  js  c++  java
  • c#设计模式(1)——单例模式

    一、引言

           最近看了一些单例模式的介绍,感觉可以总结一下,形成自己的笔记。部分内容选自https://www.cnblogs.com/zhili/p/SingletonPatterm.html,感觉写得很好,我只是再加点东西

    二、介绍

          单例模式(Singleton Pattern)是最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

          这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

         注意:

              1、单例类只能有一个实例。

              2、单例类必须自己创建自己的唯一实例。

              3、单例类必须给所有其他对象提供这一实例。

    三、多种单例模式的创建方式

        1.饿汉式创建单例模式

         说明:饿汉就是类一旦加载,就把单例初始化完成,保证CreateSingleton的时候,单例是已经存在的了。饿汉式创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成。

         

        /// <summary>
        /// 饿汉式写法
        /// </summary>
        public class SingletonEH
        {
            /**
             *是否 Lazy 初始化:否
             *是否多线程安全:是
             *实现难度:易
             *描述:这种方式比较常用,但容易产生垃圾对象。
             *优点:没有加锁,执行效率会提高。
             *缺点:类加载时就初始化,浪费内存。
             *它基于 classloder 机制避免了多线程的同步问题,
             * 不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,
             * 在单例模式中大多数都是调用 CreateSingleton 方法,
             * 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,
             * 这时候初始化 instance 显然没有达到 lazy loading 的效果。
            */
            private static SingletonEH instance = new SingletonEH();
    
            private SingletonEH()
            {
                Console.WriteLine($"{typeof(SingletonEH).Name}被构造。。。");
            }
            public static SingletonEH CreateSingleton()
            {
                return instance;
            }
        }
    

      2.懒汉式创建单例模式

            说明:而懒汉比较懒,只有当调用CreateSingleton的时候,才回去初始化这个单例。懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。

            

     /// <summary>
        /// 懒汉式
        /// </summary>
        public class SingletonLH
        {
            /**
         *是否 Lazy 初始化:否
         *是否多线程安全:是
         *实现难度:易
         *描述:这种方式比较常用,但容易产生垃圾对象。
         *优点:没有加锁,执行效率会提高。
         */
            private static SingletonLH instance = null;
    
            private SingletonLH()
            {
                Console.WriteLine($"{typeof(SingletonLH).Name}被构造。。。");
            }
    
            public static SingletonLH CreateInstance()
            {
                if(instance == null)
                {
                     return new SingletonLH();
                 }
                return instance;
            }
        }
    

      3.上面的单例模式的实现在单线程下确实是完美的,然而在多线程的情况下会得到多个Singleton实例,因为在两个线程同时运行CreateInstance方法时,此时两个线程判断(instance ==null)这个条件时都返回真,此时两个线程就都会创建Singleton的实例,这样就违背了我们单例模式初衷了,既然上面的实现会运行多个线程执行,那我们对于多线程的解决方案自然就是使CreateInstance方法在同一时间只运行一个线程运行就好了,也就是我们线程同步的问题了。

           

      public class SingletonLH
        {
            /**
         *是否 Lazy 初始化:否
         *是否多线程安全:是
         *实现难度:易
         *描述:这种方式比较常用,但容易产生垃圾对象。
         *优点:没有加锁,执行效率会提高。
         *缺点:类加载时就初始化,浪费内存。
         *它基于 classloder 机制避免了多线程的同步问题,
         * 不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,
        * 在单例模式中大多数都是调用 CreateInstance 方法,
         * 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,
         * 这时候初始化 instance 显然没有达到 lazy loading 的效果。
         */
            private static SingletonLH instance = null;
    
            private static readonly object locker = new object();
            private SingletonLH()
            {
                Console.WriteLine($"{typeof(SingletonLH).Name}被构造。。。");
            }
    
            public static SingletonLH CreateInstance()
            {
                 lock (locker)
                 {
                     if(instance == null)
                    {
                         return new SingletonLH();
                     }
                }
                return instance;
            }
        }
    

      上面代码对于每个线程都会对线程辅助对象locker加锁之后再判断实例是否存在,对于这个操作完全没有必要的,因为当第一个线程创建了该类的实例之后,后面的线程此时只需要直接判断(instance==null)为假,此时完全没必要对线程辅助对象加锁之后再去判断,所以上面的实现方式增加了额外的开销,损失了性能,为了改进上面实现方式的缺陷,我们只需要在lock语句前面加一句(instance==null)的判断就可以避免锁所增加的额外开销,这种实现方式我们就叫它 “双重锁定”

      

      public class SingletonLH
        {
          
            private static SingletonLH instance = null;
    
            private static readonly object locker = new object();
            private SingletonLH()
            {
                Console.WriteLine($"{typeof(SingletonLH).Name}被构造。。。");
            }
    
            public static SingletonLH CreateInstance()
            {
                if(instance == null)
                {
                    lock (locker)
                    {
                        if(instance == null)
                        {
                            return new SingletonLH();
                        }
                    }
                }
                return instance;
            }
        }
    

      4. 泛型封装单例模式,利于重复利用

             a.新建一个类 BaseSingleton类

              

     public class BaseSingleton<T> where T: new()
        {
            protected static T _instance;
            private static readonly object locker = new object();
    
            public static T getInstance()
            {
                if(_instance == null)
                {
                    lock (locker)
                    {
                        if(_instance == null)
                        {
                            _instance = new T();
                        }
                    }
                }
                return _instance;
            }
        }
    

      b.需要用到的类继承调用

          

     public class Singleton: BaseSingleton<Singleton>
        {
            public int Id { get; set; }
    
            public string Name { get; set; }
    
            public static void Test()
            {
                Console.WriteLine("this is Test...");
            }
        }
    

      

          

          

  • 相关阅读:
    Gof 设计模式
    系统架构师-笔记
    微信小程序弹出层点击穿透问题
    微信小程序-两个input叠加,多次点击字体变粗或闪动
    微信小程序-下拉松开弹不回去顶部留一段空白
    node+vue报错合辑
    Nodejs脚手架搭建基于express的应用
    Vue 核心之数据劫持
    Date——时间戳转化为YYYY-MM-DD h:m:s时间格式
    web页面加载、解析、渲染过程
  • 原文地址:https://www.cnblogs.com/Qxian/p/13672269.html
Copyright © 2011-2022 走看看