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

    所谓单例(Singleton)就是在应用程序运行期间,某个类型对外公布的实例始终是同一个,同一个的意思并不是说相等的,而是相同的,我们可以利用object的一个静态方法object.ReferenceEquals(而非object.Equals)来测试单例。
    1、首先,该Singleton的构造函数必须是私有的,以保证客户程序不会通过new()操作产生一个实例,达到实现单例的目的。
    2、其次,尽可能的把单例的类用sealed关键字修饰,防止类被继承。
    2、因为静态变量的生命周期跟整个应用程序的生命周期是一样的,所以可以定义一个私有的静态全局变量instance来保存该类的唯一实例;
    3、必须提供一个全局函数或者静态属性访问获得该实例,并且在该函数或者属性内部提供控制实例数量的功能,即通过if语句判断instance是否已被实例化,如果没有则用new()创建一个实例;否则,直接向客户返回一个实例。

    测试代码

    class Program
        {
            static void Main(string[] args)
            {
                Singleton instance1 = Singleton.Instance;
                Singleton instance2 = Singleton.Instance;
                bool result = object.ReferenceEquals(instance1, instance2);
                Console.WriteLine(result);
                Console.ReadKey();
            }
        }
     

    版本一

    public sealed class Singleton
        {
            private static Singleton _instance;
            private Singleton() { }
            public static Singleton Instance
            {
                get
                {
                    if(_instance==null)
                    {
                        _instance = new Singleton();
                    }
                    return _instance;
                }
            }
        }
     

    说明:这个版本中,没有考虑线程并发获取实例问题,即可能出现两个线程同时获取instance实例,且此时其为null时,就会出现两个线程分别创建了instance,违反了单例规则。

    版本二

    public sealed class Singleton
        {
            private static Singleton _instance;
            private static object obj = new object();
            private Singleton() { }
            public static Singleton Instance
            {
                get
                {
                    if(_instance==null)
                    {
                        lock (obj)
                        {
                            if (_instance == null)
                            {
                                _instance = new Singleton();
                            }
                        }
                    }
                    return _instance;
                }
            }
        }

    说明:这个和版本一唯一的区别就是保证了线程安全,使用了双重锁方式较好地解决了多线程下的单例模式实现。先看内层的if语句块,使用这个语句块时,先进行加锁操作,保证只有一个线程可以访问该语句块,进而保证只创建了一个实例。再看外层的if语句块,这使得每个线程欲获取实例时不必每次都得加锁,因为只有实例为空时(即需要创建一个实例),才需加锁创建,若果已存在一个实例,就直接返回该实例,节省了性能开销.(本人认为不需要加入volatile关键字修饰)。

    版本三

    public sealed class Singleton
        {
            private readonly static Singleton _instance = new Singleton();
            private Singleton() { }
            public Singleton Instance
            {
                get
                {
                    return _instance;
                }
            }
        }

    说明:这个版本保证了在第一次使用时Singleton已经初始化了一个实例对象,比较简单方便,比较常用,不过有一点值得我们关注,那就是和版本四的比较,显示实现静态构造函数。

    版本四

    public sealed class Singleton
        {
            private static readonly Singleton _instance = new Singleton();
            private Singleton() { }
            static Singleton() { }
            public Singleton Instance
            {
                get
                {
                    return _instance;
                }
            }
        }

    说明:这个版本和版本三基本一样,多了一个静态的构造函数,目的是为了消除IL代码中的beforefieldinit标记,在C#中,如果显示实现了静态构造函数则,则静态构造函数的执行是严格按照需要来执行的,即在第一次调用静态成员之前执行,如果没有显示实现静态构造函数,则静态构造函数的执行时机是随意的(只要保证在静态成员之前的任何时候都可以)。

    详细的请参考Artech的关于Type Initializer和 BeforeFieldInit的问题,看看大家能否给出正确的解释 和 涛哥的.Net类型构造器 

    版本五

    public sealed class Singleton
        {
            private  static readonly Lazy<Singleton> _instance = new Lazy<Singleton>(()=>new Singleton());
    
           // private static readonly Lazy<Singleton> _instance = new Lazy<Singleton>(()=>new Singleton(),System.Threading.LazyThreadSafetyMode.ExecutionAndPublication);
            private Singleton() { }
            static Singleton() { }
            public Singleton Instance
            {
                get
                {
                    return _instance.Value;
                }
            }
        }

    说明:这个版本实用了Lazy,个人感觉和版本四效果一样,都可以启到延迟加载的效果,上面注释掉的代码是设置线程安全的(由于Lazy本就是线程安全的,所以不设置也是一样的)。

    版本六(网上搜的)

     public  abstract class Singleton<T> where T:class
        {
            private static readonly Lazy<T> _instance
              = new Lazy<T>(() =>
              {
                  var ctors = typeof(T).GetConstructors(
                      BindingFlags.Instance
                      | BindingFlags.NonPublic
                      | BindingFlags.Public);
                  if (ctors.Count() != 1)
                      throw new InvalidOperationException(String.Format("Type {0} must have exactly one constructor.", typeof(T)));
                  var ctor = ctors.SingleOrDefault(c => c.GetParameters().Count() == 0 && c.IsPrivate);
                  if (ctor == null)
                      throw new InvalidOperationException(String.Format("The constructor for {0} must be private and take no parameters.", typeof(T)));
                  return (T)ctor.Invoke(null);
              });
            public static T Instance
            {
                get { return _instance.Value; }
            }
        }

    说明:这是一个单例的基类,用abstract修饰,保证所有需要实用单例的类要继承它,实用反射创建类型对象,也不用担心效率问题,因为只执行一次,好处是写一个基类之后,其它需要实现单例的类就不要写太多代码(其实也不多哦)去实现单例了,但是注意私有构造函数还是必须的。

    结束语

    对于单例,有很多的实现方式,上面是几种简单的实现模式,个人认为没必须要搞的太复杂,只需要简单实用即可,希望对你有所帮助。

  • 相关阅读:
    06软件构架实践阅读笔记之六
    05软件构架实践阅读笔记之五
    04软件构架实践阅读笔记之四
    03软件构架实践阅读笔记之三
    02软件构架实践阅读笔记之二
    01软件构架实践阅读笔记之一
    实训第四天
    实训第三天
    实训第二天
    实训第一天
  • 原文地址:https://www.cnblogs.com/skm-blog/p/Singleton.html
Copyright © 2011-2022 走看看