您的位置:首页 > 其它

Singleton patterns 单件(创建型模式)

2013-08-02 15:32 134 查看
1、模式分类

1.1 从目的来看:

• – 创建型(Creational)模式:负责对象创建。

• – 结构型(Structural)模式:处理类与对象间的组合。

• – 行为型(Behavioral)模式:类与对象交互中的职责分配。

1.2 从范围来看:

• – 类模式处理类与子类的静态关系。

• – 对象模式处理对象间的动态关系。

2、动机(Motivation)目的

在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性、以及良好的效率。

3、意图(Intent)

保证一个类仅有一个实例,并提供一个该实例的全局访问点。

——《设计模式》GoF

4、单例模式多种实现方法

4.1 单线程Singleton 模式实现

class Singleton
{
private static Singleton instance;
private Singleton() //防止外界随意new此对象,如果访问级别设置成protected,那么子类可以派生,同时也也不可以实例化此对象
{
}
public static Singleton Instance
{
get {
if (instance == null)  //起到延迟加载对象的作用,当用户用不到此实例的时候
{
instance = new Singleton();
}
return instance;
}
}
}


单线程Singleton模式的几个要点
• Singleton模式中的实例构造器可以设置为protected以允许子类派生。(同样不可实例化对象,受保护级别限制)
• Singleton模式一般不要支持ICloneable接口(实例克隆),因为这可能会导致多个对象实例,与Singleton模式的初衷违背。(实现了ICloneable接口,就必须实现Clone()方法,在此方法中我们可以返回新的对象,这样就与Singleton模式相违背了!)
• Singleton模式一般不要支持序列化,因为这也有可能导致多个对象实例,同样与Singleton模式的初衷违背。(构造对象的方式:可以通过构造器,也可以通过序列化构造对象,序列化出来的对象和原来的对象地址是不一样的,是完全的深拷贝方式(创建新的对象))
• Singletom模式只考虑到了对象创建的管理,没有考虑对象销毁的管理。就支持垃圾回收的平台和对象的开销来讲,我们一般没有必要对其销毁进行特殊的管理。
(缺点)• 不能应对多线程环境:在多线程环境下,使用Singleton模式仍然有可能得到Singleton类的多个实例对象。(在上面的代码第10行进行if判断的时候,假设现在有两个线程(A,B)同时执行到了此行,当A线程进行if判断,此时判断为null,就去实例化对象,但是A线程还没来得及进行对象的实例化的时候,此时B线程就进行了if的判断,并完成了对此对象的判断,判断为null,所以B线程就会去创建另一个实例,所以就创建了两个实例!)

4.2、多线程Singleton 模式实现

class Singleton
{
private static volatile Singleton instance = null; //volatile(编译器在对代码进行编译的时候,会对代码进行一些微调,对代码的顺序进行调整,
volatile关键字就保证了编译器不会对instance进行代码的微调,
这样就保证了严格意义上的多线程不会出现创建出多个实例的情况)
private static object lockHelper = new object(); //辅助器
private Singleton() //防止外界随意new此对象
{
}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (lockHelper)
{
if (instance == null)//双检查
{
instance = new Singleton();
}
}
}
return instance;
}
}
}


优缺点:这种实现方式对多线程来说是安全的,同时线程不是每次都加锁,只有判断对象实例没有被创建时它才加锁(如果最外层的if不加的话,那么其他线程都会进行加锁操作,会增加额外的开销,损失性能),加锁后还得再进行对象是否已被创建的判断。它解决了线程并发问题,同时避免在每个 Instance 属性方法的调用中都出现独占锁定。它还允许您将实例化延迟到第一次访问对象时发生。

volatile:

MSDN上的解释:volatile 关键字表示字段可能被多个并发执行线程修改。声明为 volatile 的字段不受编译器优化(假定由单个线程访问)的限制。这样可以确保该字段在任何时间呈现的都是最新的值

4.3、 使用.NET类型初始化机制实现多线程Singleton 模式(最好的方式)

sealed class Singleton
{
private static readonly Singleton instance = new Singleton();
private Singleton() //防止外界随意new此对象
{
}
}


其实上面的代码实现如果展开来的话等同于下面代码的实现

sealed class Singleton
{
private static readonly Singleton instance;
static Singleton() //在调用instance静态字段时会先去执行此静态构造器,静态构造器能保证多线程环境下只有一个线程执行了此静态构造器,为我们自动加锁
{
instance = new Singleton();//在静态构造器中实例化
}
private Singleton() //防止外界随意new此对象
{
}
}


该类标记为 sealed 以阻止发生派生,而派生可能会增加实例。此外,变量标记为 readonly,这意味着只能在静态初始化期间(此处显示的示例)或在类构造函数中分配变量。

缺点:

我们对实例化机制的控制权较少!在4.1和4.2中能够在实例化之前使用非默认的构造函数或执行其他任务。由于在此实现方法中由 .NET Framework负责执行初始化,因此您没有这些选项。

无法实现延迟初始化,

4.3的实现方法无法进行传参,4.1和4.2的实现方式都可以进行传参,主要是因为对象的实例化是在方法内部创建的(属性实质为方法),所以我们可以把属性写成带参数的方法即可!如下,对4.1方法变为带参数的!

class Singleton
{
private static Singleton instance;
public string Name { get; set; }
public int Age { get; set; }
public static Singleton GetInstance(string name, int age)
{
if (instance == null)
{
instance = new Singleton(name, age);
}
return instance;
}
private Singleton(string name, int age)
{
this.Name = name;
this.Age = age;
}
}


5、延迟初始化

public sealed class Singleton
{
Singleton()
{
}
public static Singleton Instance
{
get
{
return Nested.instance;
}
}
class Nested
{
static Nested()
{
}
internal static readonly Singleton instance = new Singleton();
}
}


这里,初始化工作有Nested类的一个静态成员来完成,这样就实现了延迟初始化,并具有很多的优势,是值得推荐的一种实现方式

6、Singleton模式扩展
• 将一个实例扩展到固定几个实例,例如对象池的实现。这样做是允许的而且是有意义的!
• 将new 构造器的调用转移到其他类中,例如多个类协同工作环境中,某个局部环境只需要拥有某个类的一个实例。
• 理解和扩展Singleton模式的核心是“如何控制用户使用new对一个类的实例构造器的任意调用”。

7、.NET框架中的Singleton应用

winform程序,你只需要点击按钮,弹出一个窗口,并且保证此窗口只能有一个!再点击按钮是无法在弹出此窗体的!

PC机中可能有几个串口,但只能有一个COM1口的实例。

系统中只能有一个窗口管理器。

.NET Remoting中服务器激活对象中的Sigleton对象,确保所有的客户程序的请求都只有一个实例来处理。

8、推荐参考书
• 《设计模式:可复用面向对象软件的基础》GoF --小白看起来会有点困难
• 《面向对象分析与设计》Grady Booch --翻译有些问题
• 《敏捷软件开发:原则、模式与实践》Robert C. Martin
• 《重构:改善既有代码的设计》 Martin Fowler
• 《Refactoring to Patterns》Joshua Kerievsky --没中文版

9、参考

《C#面向对象设计模式纵横谈》 李建忠

http://terrylee.cnblogs.com TerryLee

作者:MrZivChu

2013-08-02 15:34:03
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: