Singleton单件(创建型模式)
模式分类:
从目的来看:
创建型(Creational)模式:负责对象创建
常规的对象创建方式:new对象
结构型(Structural)模式:处理类与对象间的组合
这个类是组合的关系更好,继承的依赖性太强。
行为型(Behavioral)模式:类与对象交互中的职责分配。
从范围来看:
类模式处理类与子类的静态关系;
对象模型处理对象间的动态关系。
动机(Motivation)
在软件系统中,经常有这样一些特殊的类,必须保证它们在系统
中只存在一个实例,才能确保它们的逻辑正确性、以及良好的效率。
如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?
这应该是类设计者的责任,而不是使用者(客户程序)的责任。
意图(Intent):满足动机,保证类只有一个实例,并提供一个
该实例的全局访问点。
Singleton单件最基本的实现代码举例
public class Singleton
{
//静态私有字段,不希望外界直接去访问它
private static Singleton instance;
//私有实例构造器,空的实现。意义:让这个类的使用
者调不到这个构造器,防止外界使用new来创建它,
如果把这个代码注释掉,则可以调用
private Singleton(){}
//静态只读属性
pubuli static Singleton Instance
{
get
{
//提倡使用这种,晚加载,如果客户不需要这个实例
就不要去new它
if(instance==null)
{
//在类型里边可以调用new
instance=new Singleton();
}
return instance;
}
}
}
class Test
{
public Static void Main()
{
//如果把上面这句代码private Singleton(){}
注释掉,则调用者可以new实例,这不是我们想要的
//Singleton t=new Singleton();
singleton t1=Singleton.Instance;
singleton t2=Singleton.Instance;
//t1和t2是相等的,可以测试一下
Console.WriteLine(Object.ReferenceEquals(t1,t2)==true);
}
}
Singleton单件最基本的实现代码举例2(这么写也行)
public class Singleton
{
//静态私有字段,不希望外界直接去访问它
private static Singleton instance=new Singleton();
private Singleton(){}
//静态只读属性
pubuli static Singleton Instance
{
get
{
return instance;
}
}
}
Singleton模式一般不要去序列化。创建对象最初始的可以通过
构造器创建,但如果你已经有了一个对象,可以把这个对象序列化
到一个内存流中或到一个硬盘文件中,然后在做一个反序列化,
它就会出来一个新的实例。这个实例的引用和原来的地址是不一样
的。
Singleton模式只考虑了对象创建的管理,没有考虑对象销毁的管理
并不是我们不愿意去考虑,而是考虑它的收获不大。1、对于支持垃圾
回收的平台,垃圾回收会自己回收(在类型卸载的时候被回收),
不会导致内存泄露。2、往往是因为我们引用了一个静态字段,而
且只能读不能写,一旦初始化之后,它就是一个全局的根对象。
就不能被回收。而且这个对象的开销不到,仅仅只有一个
Singleton模式不能应对多线程模式:使用多线程仍有可能得到
类的多个实例。一个线程到了if处,判断为空,往下走但没有创建
实例,另一个线程也到了if处,这样就有可能new多个实例。
多线程的单一实例不能保证
多线程Singleton模式设计:
public class Singleton
{
//加了一个volatile修饰,可以保证特定平台的实现必须
不要去重新调整指令,以保证对象构造非常严格的顺序,
如果把这个关键字去掉,还是有可能出现多个实例
private static volatile Singleton instance=null;
//一个辅助器,本身不参与真正意义上的构建
private static object lockHelper=new Object();
//私有构造器
private Singleton() { }
//静态属性,这里也可是方法,如果是方法,把get去掉即可
pubuli static Singleton Instance
{
get
{
if(instance==null)
{
//加锁
lock(lockHelper)
{
//双检查DoubleCheck目的:使用lock语句来避免多线程的访问
if(instance==null)
{
instance=new Singleton();
}
}
}
}
}
}
多线程Singleton模式设计2:(别看代码简单,也全部实现了singletonmos的
要求,有一点点弊端:不支持参数化的Singleton,不支持构造器接收参数)
class Singleton
{
//内敛初始化:在声明的同时进行了初始化,内敛初始化
会把初始化拉到真正的构造器中进行初始化
public static readonly Singleton Instance=new Singleton();
private Singleton(){};
}
上面两句代码等同于以下代码:
class Singleton
{
//静态字段
public static readonly Singleton Instance;
//放在静态构造器进行初始化,静态构造器充当的角色:
1、静态构造器的执行时间只在静态字段初始化之前执行
static Singleton()
{
//初始化
Instance=new Singleton();
}
private Singleton(){ }
}
class Test
{
public static void Main()
{
//.net类型初始化机制保证这个字段被访问之前,
肯定要先先走静态构造器,可以精确的保证。
这是第一点,我们保证了只要你访问这个Instance,
就能够达到字段被实例化这么一个目的。第二点,这个
实例还要保证能够进行一个环视评估,如果我们不用就
不会对其进行实例化。第三点是为什么能够支持多线程
环境下的singleton模式呢?是因为静态构造器可以保证
多线程环境下只有一个线程执行了这个构造器,不可能有
多个线程去执行构造器。.net机制会免费给
—-static Singleton()
—-{
—-//初始化
—-Instance=new Singleton();
—-}这个代码加锁。
Console.WriteLine(Singleton.Instance);
}
}
静态构造器不支持参数,所有不能传参,使用构造属性的方式实现
class Singleton
{
public static readonly Singleton Instance=new Singleton();
private Singleton(){};
//辅助函数,专门做一些初始化的工作
public void Init(FileStream fs)
{
//可以在这里做一些资源的处理初始化工作
}
//属性
public int X
{
get{return this.x;}
set{this.x=x}
}
public int Y
{
get{return this.y;}
set{this.y=y;}
}
int x;
int y;
}
class Test
{
public static void Main()
{
Singleton instance=Singteton.Instance();
//先做一个资源初始化的调用
instance.Init=(new FileStream("...."));
instance.X=100;
instance.Y=200;
Console.WriteLine(instance);
}
}
高手写的代码不是让人觉得这个东西好复杂,真正令人惊颤的代码
是看到你的代码哦好简单啊,我怎么没想到。能够用简单的东西
来实现复杂的东西。其实是大家追求的一个境界
面向对象设计案头必备:
《设计模式:可复用面向对象软件的基础》
《设计模式:可复用面向对象软件的基础》GoF
《敏捷软件开发:原则、模式与实践》Robert C.Marhin
《重构:改善既有代码的设计》 Martin Fowler