Singleton 与 MonoState 模式
1. Singleton 模式的不同实现形式
1) 最简单的Sigleton (无线程同步, 不适应多线程环境)
using System;
public class Singleton
{
private static Singleton instance;
private Singleton() { }
public static Singleton GetInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
2) 著名的Double check 方式(有同步控制, 可以用于多线程环境)
这种方式实现也不复杂,需要注意的是,在.Net 平台下,由于优化的需要,JIT 编译器有
可能调整语句顺序,因此要使用易失字段(C#使用volatile 关键字)避免这种情况的发生。
using System;
public class Singleton
{
private static volatile Singleton instance;
private static readonly object lockHelper = new object();
private Singleton() { }
public static Singleton GetInstance() {
if (instance == null) {
lock(lockHelper) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
3) 事实上,.net编译器可能为我们带来麻烦,同时我们也可以利用.net运行时的特点实现更为
简洁的多线程Singleton, 那就是 static 构造器,我们知道,static 构造函数是由.net
runtime 调用的,用户不可直接调用,并且它保证即使在多线程模式下,static 构造函数
也只会被执行一次,也可以这么说,.net 运行时免费为我们加了锁,那么我们就可以利用这个
特点,来实现更为简洁的Singleton (当然也适应多线程环境), 实现如下:
using System;
public class Singleton
{
private static Singleton instance;
static Singleton() {
instance = new Singleton();
}
private Singleton() { }
public static Singleton GetInstance() {
return instance;
}
}
如果我们更加的崇尚简洁,则可以使用内联的方式来初始化instance, 实现如下:
using System;
public class Singleton
{
private static Singleton instance = new Singleton();
private Singleton() { }
public static Singleton GetInstance() {
return instance;
}
}
当然,更为简洁的做法是:
using System;
public class Singleton
{
public static readonly Singleton Instance = new Singleton();
private Singleton() { }
}
Singleton 模式的主要优点:
1). 适用于任何类.
2). 可以通过派生创建,无论基类是否为Singleton, 子类都可以实现为Singleton。
3). Lazy loading: 如果从来没有使用过一个Singleton 类, 它就不会占用内存。
Sigleton 模式的代价:
1). 销毁方法没有定义:Singleton 一旦被加载,将一直存在于内存,直到应用程序卸载,无法销毁,
即使将其设置为null, 系统的各个对象仍然可能拥有它的引用,再次调用时,将再次产生一个实
例,如果在C++ 这个的系统中,这样的操作还有可能导致系统的崩溃。
2). 效率问题:每次调用都要执行if 语句,而大部分情况下是多余的,不过这个问题只在第一种方式实现的
Singleton 模式中存在。
3). Singleton 的子类天然不是Singleton, 必须重新实现。
4). 丧失多态性。
5). 不透明性:客户程序必须知道它正在使用一个Singleton, 因为必须使用GetInstance() 才能创建
实例。
2. MonoState 的实现及其与Singleton 的比较
Monostate是另一种获得“系统某个类别对象都表现为一个对象”的实现方式,Singleton模式重在
通过保证系统中只有唯一实例,而Monostate模式重在保证唯一状态, 当然Singleton模式更多的是用来
保证唯一实例。
Monostate模式更多关注的是行为,即行为上的一致;Singleton模式更多关注的是结构,强制结构上的
单一,仅产生唯一实例,下面是MonoState 模式的实现:
using System;
public class Mono
{
private int a;
private int b;
public Mono(int a, int b) {
this.a = a;
this.b = b;
}
public int A {
get {
return this.a;
}
set {
this.a = value;
}
}
public int B {
get {
return this.b;
}
set {
this.b = value;
}
}
}
public class MonoState
{
private static Mono mono;
public MonoState() {
mono = new Mono(10, 20);
}
public Mono Mono {
get {
return mono;
}
set {
mono = value;
}
}
}
internal static class TestApp
{
private static void Main() {
MonoState monoState1 = new MonoState();
monoState1.Mono.A = 200;
MonoState monoState2 = new MonoState();
monoState2.Mono.B = 400;
Console.WriteLine(object.ReferenceEquals(monoState1.Mono, monoState2.Mono));
}
}
Monostate模式比Singleton模式有着一些优势和特点:
1). 没有到底谁负责销毁的问题,你可以在你不想Monostate对象的时候将它销毁,因为它和任何
其他的对象没有任何区别。
2). MonoState 的子类天然就是MonoState。
3). 可以表现多态性,因为Mono 属(或者实现为两个方法)不是static 的,因此可以override.
4). 透明性:用户并不需要也不关心是否使用了Monostate模式对象,原因还是Monostate对象和其
他对象是一样的。
当然Monostate模式也有自己的限制和代价:
1). 内存占用:即使不使用Monostate对象,也要占用内存,因为有static成员变量。
2). 效率:因为Monostate模式中创建的是真正的对象,因此需要创建和销毁开销。
3). 不可转换:无法把一个非MonoState 的对象通过子类化变为MonoState.
参考: Agile Software Development
Principles, Patterns, and Practices