C#面向对象设计模式纵横谈2 Singleton单件创建型模式

来源:互联网 发布:java 同步锁 编辑:程序博客网 时间:2024/06/05 10:41

Singleton单件(创建型模式)

模式分类:
从目的来看:
创建型(Creational)模式:负责对象创建
常规的对象创建方式:new对象
结构型(Structural)模式:处理类与对象间的组合
这个类是组合的关系更好,继承的依赖性太强。
行为型(Behavioral)模式:类与对象交互中的职责分配。

从范围来看:
类模式处理类与子类的静态关系;
对象模型处理对象间的动态关系。

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

如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?

这应该是类设计者的责任,而不是使用者(客户程序)的责任。

意图(Intent):满足动机,保证类只有一个实例,并提供一个
该实例的全局访问点。

Singleton单件最基本的实现代码举例

public class Singleton{    //静态私有字段,不希望外界直接去访问它    private static Singleton instance;    //私有实例构造器,空的实现。意义:让这个类的使用    者调不到这个构造器,防止外界使用new来创建它,    如果把这个代码注释掉,则可以调用    private Singleton(){}    //静态只读属性    pubuli static Singleton Instance    {        get        {            //提倡使用这种,晚加载,如果客户不需要这个实例            就不要去newif(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

0 0
原创粉丝点击