设计模式学习笔记一:单例模式(Singleton)

  单例模式是我们在软件设计中比较常用的一种设计模式,当我们需要保证某些类在软件系统中只能存在一个实例时就可以考虑使用单例模式了。单例模式保证了一个类仅有一个实例,并且提供一个该实例的全局访问点。下面是一个最简单单例模式的示例:

    class Singleton
    {
        private static Singleton instance;

        private Singleton() { }

        public static Singleton Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new Singleton();
                }
                return instance;
            }
        }
    }

  示例中我们申明了一个private的构造函数,保证在外部调用时该类不会被new出一个实例,只能通过只读属性Instance来得到类的实例。这种方式在单线程开发中是完全没有问题的,但在多线程中,当一个线程刚刚进入if语句块,另一个线程在执行if语句块时instance还会是null,这样Singleton就会被创建多个实例了,已经无法达到单例模式的意图。为了适应多线程,我们可以使用在多线程开发中常用的lock语句块,来改写我们的上个示例。

 class Singleton
 {
        private static volatile Singleton instance;
        private static object lockObject = new object();
        private Singleton() { }

        public static Singleton Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (lockObject)
                    {
                        if (instance == null)
                        {
                            instance = new Singleton();
                        }
                    }
                }
                return instance;
            }
        }
 }

   lock关键字能够确保当一个线程进入代码的临界区时,另一个线程不进入临界区,如果其它线程试图进入锁定的代码段,则它将一直被阻塞,直到被锁定的对象被释放才能进入。在这个示例中我们对instance使用了volatile关键字,volatile修饰符表示所申明的字段能够被多个并发执行的线程更改,并且被修饰的字段将不再被编译器优化,这样可以确保该字段在任何时间呈现的都是最新的值。

  除此之外单例模式还有一种比较简单的实现方式,那就是利用静态构造函数,我们知道静态构造函数只在该类的静态字段被实例化的时候执行,并且只会执行一次,所以我们也可以这样来实现单例模式

    class Singleton
    {
        public static readonly Singleton Instance;

        static Singleton()
        {
            Instance = new Singleton();
        }
        private Singleton() { }
    }

 或者使用下面更为简洁的代码实现:

    class Singleton
    {
        public static readonly Singleton Instance = new Singleton();
        private Singleton() { }
    }

  这两种方式其实质其实是一模一样的,因为Instance在被实例化时会调用Singleton的静态构造函数,只是这样代码更为简洁明了,但是这样写也有一个缺点,就是不能给构造函数传参数了,但是这样又有什么关系呢,我们通过给对象的成员变量直接赋值,完全可以达到一样的效果,这样还可以将构造函数所承担的内存分配和成员初始化相分开,何乐而不为呢。当然如果非得为构造函数传参那就只能改写第一种或第二种方式了。

 class Singleton
 {
        private static volatile Singleton instance;
        private static object lockObject = new object();
        private Singleton(String name)
        {
            this.name = name;
        }
        private String name;
        public String Name
        {
            get
            {
                return this.name;
            }
            set
            {
                this.name = value;
            }
        }
        public static Singleton GetInstance(String name)
        {
            if (instance == null)
            {
                lock (lockObject)
                {
                    if (instance == null)
                    {
                        instance = new Singleton(name);
                        return instance;
                    }
                }
            }
            instance.name = name;
            return instance;
        }
 }

  好了,单例模式的总结就先到这里。

原文地址:https://www.cnblogs.com/psforever/p/2543738.html