C# 设计模式(1)-----单例模式

一、引言

       最近在看设计模式,同时在学习过程中也查看了大量的博客,也查阅了很多关于设计模式的一些文章的,在此,特别记录下我的学习笔记,加深自己对设计模式理解,同时可以给一些初学设计模式的朋友提供查阅的路径。

二、单例模式的介绍

       单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。单例模式常用 singleton 表示,singleton 在数学与逻辑学中定义为“有且仅有一个元素的集合”。

三、为什么会有单例模式,目的动机是啥?

       对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。

四、实现思路

       从单例模式的概念入手,一:确保一个类只有一个实例;二:只有一个全局访问点,下面就开始实现代码编写:

 public class Singleton
    {
        //定义静态变量存储实例
        private static Singleton uniqueInstance;

        //定义私有构造函数,外界不可通过 new 创建该实例
        private Singleton()
        {
        }

        /// <summary>
        /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
        /// </summary>
        /// <returns></returns>
        public static Singleton GetInstance()
        {
            // 如果类的实例不存在则创建,否则直接返回
            if (uniqueInstance==null)
            {
                Singleton uniqueInstance = new Singleton();
            }
            return uniqueInstance;
        }
    }

      单例模式在单线程运行下是完美的,但是在多线程下会得到多个Singleton实例,因为两个线程同时运行GetInstance方法,对多线程的解决方案自然就是使GetInstance方法在同一时间只运行一个线程运行就好了,这里,引入线程锁机制:

 public class Singleton
    {
        //定义静态变量存储实例
        private static Singleton uniqueInstance;

        //定义一个锁,用来标识线程的状态
        public static readonly object locker = new object();

        //定义私有构造函数,使得外界不可以通过 new 创建该实例
        private Singleton()
        {
        }

        /// <summary>
        /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
        /// </summary>
        /// <returns></returns>
        public static Singleton GetInstance()
        {
            //当线程运行到这里,判断locker对象有没有加锁, 没有加锁,则会对locker对象 "加锁",
            //使得第二个线程到达这里时会被挂起,只有等到前一个线程运行完lock对该对象"解锁"后才会继续
            lock (locker)
            {
                // 如果类的实例不存在则创建,否则直接返回
                if (uniqueInstance == null)
                {
                    Singleton uniqueInstance = new Singleton();
                }
            }           
            return uniqueInstance;
        }
    }

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

    public class Singleton
    {
        //定义静态变量存储实例
        private static Singleton uniqueInstance;

        //定义一个锁,用来标识线程的状态
        public static readonly object locker = new object();

        //定义私有构造函数,使得外界不可以通过 new 创建该实例
        private Singleton()
        {
        }

        /// <summary>
        /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
        /// </summary>
        /// <returns></returns>
        public static Singleton GetInstance()
        {
            //双重锁机制
            if (uniqueInstance == null)
            {
                //当线程运行到这里,判断locker对象有没有加锁, 没有加锁,则会对locker对象 "加锁",
                //使得第二个线程到达这里时会被挂起,只有等到前一个线程运行完lock对该对象"解锁"后才会继续
                lock (locker)
                {
                    // 如果类的实例不存在则创建,否则直接返回
                    if (uniqueInstance == null)
                    {
                        Singleton uniqueInstance = new Singleton();
                    }
                }
            }
            return uniqueInstance;
        }
    }

五、总结

到此,设计模式的单例模式介绍完了,希望大家可以对单例模式有一个更深的理解,并且希望之前没接触过单例模式或觉得单例模式陌生的朋友看完之后或有所感悟

猜你喜欢

转载自blog.csdn.net/qq_21419015/article/details/82177506
今日推荐