首页 > 代码库 > 设计模式之单例模式

设计模式之单例模式

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

结束语

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

 

设计模式之单例模式