设计模式(六)—— 单例模式

单例模式

模式简介

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

简单来说,让类自己负责保存它的唯一实例(静态私有变量),通过使用受保护的构造函数来保证没有其他实例可以被创建,并且提供一个访问该实例的公有方法(公有的静态方法),这就是单例(Singleton)模式。

结构说明

UML类图

职责及说明

  • Singleton

定义一个Instance方法,允许客户访问它的唯一实例

示例分析

创建Singleton类

class Singleton
{
    //静态变量instance保存唯一实例
    private static Singleton instance;

    //私有化构造函数,保证唯一实例的受控访问
    private Singleton()
    {

    }

    //提供访问该实例的静态方法
    public static Singleton Instance()
    {
        if (instance == null)
        {
            instance = new Singleton();
        }
        return instance;
    }
}

客户端调用

static void Main(string[] args)
{
    Singleton s1 = Singleton.Instance();
    Singleton s2 = Singleton.Instance();
    Console.WriteLine(s1 == s2);
    Console.ReadLine();
}

输出结果

懒汉式单例类与饿汉式单例类

对于多线程的程序,调用以上示例中的Instance方法可能创建多个实例。

懒汉式

为了解决线程安全的问题,我们可以通过给进程加锁来处理。

class LazySingleton
{
    private static LazySingleton instance;
    private static readonly object syncRoot = new object();
    private LazySingleton()
    {

    }

    public static LazySingleton Instance()
    {
        if (instance == null)
        {
            lock (syncRoot)
            {
                if (instance == null)
                {
                    instance = new LazySingleton();
                }
            }
        }
        return instance;
    }
}

这种在第一次引用时才会实例化的方式被称为懒汉式单例类。如同一个懒汉已经饿到不行了才去吃东西(需要使用实例时才去创建对象)。

饿汉式

class EagerSingleton
{
    private static EagerSingleton instance = new EagerSingleton();
    private EagerSingleton()
    {

    }
    public EagerSingleton Instance()
    {
        return instance;
    }

}

这种使用静态初始化,在类被加载时就进行实例化的方式被称为饿汉式单例类。如同一个人被饿怕了,不管需不需要,先把吃的买好了存起来(不管是否会使用该实例,总是在类加载时就创建好实例)。

适用场景

  • 当类只能有一个实例而且客户可以从一个公共的访问点获取它时
  • 当这个唯一实例应该是通过子类化可扩展时,并且客户应该无需修改代码就能使用一个扩展的实例时

优缺点

优点

  • 保证唯一实例的受控访问
  • 节约系统资源。对于一些需要频繁创建和销毁的对象,单例模式无疑可以提高系统的性能
  • 允许可变数目的实例。使用与单例控制相同的方法(if instance == null)指定对象实例的个数。

缺点

  • 由于单例模式中没有抽象层,所以扩展起来难度较大
  • 违反了单一职责原则。因为单例类既要提供公有的访问方法,又要提供该实例的业务方法
  • 不合理地滥用单例模式可能会造成一些负面问题。如将数据库连接池对象设计成单例类,可能会导致共享连接池对象的程序过多而出现连接溢出;另外如果实例化的对象长时间不被利用,可能出现状态丢失

源码下载

dotnet-design-pattern_singleton

posted @ 2018-05-19 16:56 Answer.Geng 阅读(...) 评论(...) 编辑 收藏