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

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值