近期做项目时初期设计某个模块时,同事说应该用简单工厂模式,我只听说过简单工厂模式但不太了解。我把写的demo给他看,同事一看说这就是简单工厂呀,瞬间感觉弱爆了,还是要加强理论知识呀,工作两年了,对设计模式只是听听名称,一直没去专研。下了个大话设计模式电子书,大概过了一遍,准备把现在工作接触到的先研究做个记录。
先从软柿子捏了,单例模式是听得最多的也是我认为最简单的,不过学习了之后还是有颇多收获。学习的过程也找了几种实现方式:
方法一:
public class Singleton
{
private static Singleton instance;
//私有构造函数,不让外界构造实例
private Singleton() { }
//开放实例的全局访问点
public static Singleton GetInstance()
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
这种方式的缺点是多线程时不能保证单一实例;
由此引入第二种方法,保证在多线程下单一实例:
/// <summary>
/// 懒汉式单例类-双重锁定
/// </summary>
public class Singleton
{
private static Singleton instance;
private static readonly object syncRoot = new object();
//私有构造函数,不让外界构造实例
private Singleton() { }
//开放实例的全局访问点
public static Singleton GetInstance()
{
//只有当实例未创建时才锁
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
不过C#还有简单的实现,静态初始化:
/// <summary>
/// 饿汉式单例类-静态初始化
/// </summary>
public sealed class Singleton
{
private static readonly Singleton instance=new Singleton();
//私有构造函数,不让外界构造实例
private Singleton(){}
//开放实例的全局访问点
public static Singleton GetInstance()
{
return instance;
}
}
这种静态初始化的方式是在自己被加载时就将自己实例化,所以被形象的称之为饿汉式单例类,而方法二要在第一次被引用时才会被实例化,所以称为懒汉式单例类。
后来查看相关的文章发现还有好多实现方法,特别有一种方法是对方法三的优化:
/// <summary>
/// 饿汉式单例类-静态初始化--延时初始化
/// </summary>
public sealed class Singleton
{
// 因为下面声明了静态构造函数,所以在第一次访问该类之前,new Singleton()语句不会执行
private static readonly Singleton instance = new Singleton();
//私有构造函数,不让外界构造实例
private Singleton() { }
// 声明静态构造函数就是为了删除IL里的BeforeFieldInit标记
// 以去除静态变量在使用之前被初始化
static Singleton() { }
//开放实例的全局访问点
public static Singleton GetInstance()
{
return instance;
}
}
方法三需要注意的是,C#其实并不保证实例创建的时机,因为C#规范只是在IL里标记该静态字段是BeforeFieldInit,也就是说静态字段可能在第一次被使用的时候创建,也可能你没使用了,它也帮你创建了,也就是周期更早,我们不能确定到底是什么创建的实例。而方法四保证了是个延迟初始化的单例(通过加静态构造函数),要注意的是该静态构造函数里没有东西,所以实际写时要加上注释防止被后期维护的人删掉。
参考:
1.大话设计模式,程杰;
2.博客园的汤姆大叔。