单例模式
问题:如何保证一个类只创建一个对象,且该对象全局共享
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点
适用性:当类只有一个实例而且客户端可以从一个从所周知的访问点访问,当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展实例时。
总结:单例模式就是保证系统中一个类只有一个实例。也就是说只能自己new自己并且实例唯一并对外提供。
优点:
- 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。
- 避免对资源对过多占用。
缺点:
- 没有抽象层,不能继承扩展很难。
- 违背了“单一职责原则”,一个类只重视内部关系,而忽略外部关系。
- 不适用于变化对象。
- 滥用单例会出现一些负面问题,如为节省资源将数据库连接池对象设计为单例,可能会导致共享连接池对象对程序过多而出现连接池溢出。如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这样将导致对象状态丢失。
解决方案【步骤】
- 创建一个类
- 定义一个私有的构造函数
- 定义一个私有静态的变量指向自己
- 定义一个公有静态的方法用于返回自己类的唯一实例
单例模式基本实现方式
1、饿汉模式
描述:这种方式比较常用,但容易产生垃圾对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
using System;
public class Singleton
{
//定义一个私有静态的变量指向自己
private static Singleton _instance = new Singleton();
//定义一个私有的构造函数
private Singleton() { }
//定义一个公有静态的方法用于返回自己类的唯一实例
public static Singleton instance()
{
return _instance;
}
}
2、懒汉模式(线程不安全)
描述:懒汉模式申明了一个静态对象,在用户第一次调用时初始化,虽然节约了资源,但第一次加载时需要实例化,反映稍慢一些,而且在多线程不能正常工作。
using System;
public class Singleton
{
//定义一个私有静态的变量
private static Singleton _instance;
//定义一个私有的构造函数
private Singleton() { }
//定义一个公有静态的方法用于返回自己类的唯一实例
public static Singleton instance()
{
if (_instance == null)
_instance = new Singleton();
return _instance;
}
}
3、双重加锁机制
描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
using System;
public class Singleton
{
//程序运行创建一个只读(readonly)的(object)进程辅助对象
public static readonly object sync = new object();
//定义一个私有静态的变量
private static Singleton _instance;
//定义一个私有的构造函数
private Singleton() { }
//定义一个公有静态的方法用于返回自己类的唯一实例
public static Singleton instance()
{
//判断是否存在
if (_instance == null)
{
//加锁 只有一个线程可以进入
lock (sync)
{
if(_instance==null)
_instance = new Singleton();
}
}
return _instance;
}
}
静态初始化
描述:这种方式能达到双检锁方式一样的功效,但实现更简单。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
using System;
public class Singleton
{
//在第一次引用类的任何成员时创建实例,
//公共语言运行库负责处理变量初始化
private static readonly Singleton _instance = new Singleton();
//定义一个私有的构造函数
private Singleton() { }
//定义一个公有静态的方法用于返回自己类的唯一实例
public static Singleton instance()
{
return _instance;
}
}
测试用例
using System;
class Program
{
static void Main(string[] args)
{
//单例模式不能自己new自己
//Singleton Obj = new Singleton();
//获得唯一可用的对象
Singleton obj = Singleton.instance();
Singleton obj1 = Singleton.instance();
//判断两个实例是否是同一实例
Console.WriteLine(obj == obj1);
Console.Read();
}
}