模式简介
保证一个类仅有一个实例,并提供一个访问它的全局访问点
简单来说,让类自己负责保存它的唯一实例(静态私有变量),通过使用受保护的构造函数来保证没有其他实例可以被创建,并且提供一个访问该实例的公有方法(公有的静态方法),这就是单例(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)指定对象实例的个数。
缺点
-
由于单例模式中没有抽象层,所以扩展起来难度较大
-
违反了单一职责原则。因为单例类既要提供公有的访问方法,又要提供该实例的业务方法
-
不合理地滥用单例模式可能会造成一些负面问题。如将数据库连接池对象设计成单例类,可能会导致共享连接池对象的程序过多而出现连接溢出;另外如果实例化的对象长时间不被利用,可能出现状态丢失。