关于单例模式----这些你都知道吗?

前言

  这篇是个人总结C#设计模式系列文章的第一篇,本系列文章将由浅入深的研究C#开发中常用到的各种设计模式。欢迎大家批评指正。

  本篇将从单例模式的基本概念开始,由浅入深探究C#中单例模式的几种不同的实现方法,并分析其中的区别和各自的适用范围(有点啰嗦,大侠请直接跳过前面)。

基本概念

  单例模式属于创建型模式,其意图是保证一个类只有一个实例,并提供一个可以访问它的全局访问点。对于一些情况只有一个实例很重要,例如一个用户登陆了一个系统之后经常在不同模块之间点击,理论上所有模块应该共用同一个Login对象。而如何才能保证一个类只有一个实例并且很容易被访问呢?最简单的方法就是让类本身保存它的唯一实例,也就是单例模式。

1、基本实现(惰性加载、懒汉模式)

 1 public sealed class Singleton 
 2     {
 3         public static Singleton singletonInstance;
 4         private Singleton() { }
 5         public static Singleton getSingletonInstance() 
 6         {
 7             if (singletonInstance == null)
 8             {
 9                     singletonInstance = new Singleton();
10             }
11             return singletonInstance;
12         }
13     }

  这种实现方式最常见,对于适用于单线程的小应用程序,通过懒加载避免了在应用程序启动时创建了不必要的实例。缺点也很明显,这种实现不是线程安全的,在多线程环境下有可能会得到多个类的实例(多个线程同时访问singletonInstance == null时)。

2、双重锁定

要想实现线程安全也很简单,使用lock即可(类似于java中的synchronized),代码如下:

 1     public sealed class Singleton 
 2     {
 3         public static Singleton singletonInstance;
 4         private static readonly object temp_lock = new object();
 5         private Singleton() { }
 6         public static Singleton getSingletonInstance() 
 7         {
 8             if (singletonInstance == null)
 9             {
10                 lock (temp_lock)
11                 {
12                     if (singletonInstance == null)
13                     {
14                         singletonInstance = new Singleton();
15                     }
16                 }
17             }
18             return singletonInstance;
19         }
20     }

  lock关键字可以保证代码块被完整运行,不会被其他线程打断。temp_lock是一个进程辅助对象,线程在进入时先对辅助对象加锁然后再检测对象是否被创建,这样就可以确保只有一个实例被创建。在第10行处才加锁,可以减少一部分开销,不必每次都加锁。这种实现解决保证了线程安全,也实现了延迟加载,

3、饿汉模式

  这种方式实现起来最简单,最常用,而且也是线程安全的, 由于构造函数是私有的,不会在类的外部被创建,而Singleton 实例被私有静态成员变量引用,所以在类的getSingletonInstance方法被首次调用之前,不会发生实例化。

    public sealed class Singleton 
    {
        private static Singleton singletonInstance = new Singleton();
        private Singleton() { }
        public static Singleton getSingletonInstance() 
        {
            return singletonInstance;
        }
    }

  这种方法的缺点就是不能在对象实例化之前做执行其他任务,类被加载时,CLR会自动实例化这个类,而不是在第一次调用GetInstance()后才实例化。

4、内部类

    public sealed class Singleton
    {
        private Singleton() { }
        private static class SingletonHolder{
            internal static readonly Singleton singletonTnstance = new Singleton();
        }
        public static Singleton getSingletonInstance
        {
            get
            {
                return SingletonHolder.singletonTnstance;
            }
        }
    }

  使用这种方法初始化工作由SingletonHolder的一个静态成员来实现,可以实现延迟初始化,尤其是当实例化instance很消耗资源时更具备优势,上述几种的其他优点这里也具备,是值得推荐的一种实现方式。

  由于C#中的enum类型不支持方法,所以不能像java中那样通过enum实现单例模式。

总结:

  其实单例模式的只要思想在于“如何控制用户使用new对一个类的构造器的任意调用”。另外上述实现方法中没有考虑对象销毁的管理,当然对于.NET来说,这方面一般不需要我们来考虑。

  同时单例模式有以下个优点:

  1、保持对象状态一致,阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。

  2、可以作为对全局变量的一种改进方式,避免一些存储唯一实例的全局变量。

  3、内存开销,相对于创建多个实例,减少内存开销。

                                                                    (暂时整理这么多了,有其他问题再补充。)

原文地址:https://www.cnblogs.com/Legolas/p/SingletonPattern.html