一、为什么使用单例
由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁地创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。由于单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后用永久驻留内存的方式来解决。单例模式可以避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。单例模式可以在系统设置全局的访问点,优化和共享资源访问
二、单例模式的缺点
单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。单例模式为什么不能增加接口呢?因为接口对单例模式是没有任何意义的,它要求“自行实例化”,并且提供单一实例、接口或抽象类是不可能被实例化的。当然,在特殊情况下,单例模式可以实现接口、被继承等,需要在系统开发中根据环境判断。单例模式对测试是不利的。在并行开发环境中,如果单例模式没有完成,是不能进行测试的,没有接口也不能使用mock的方式虚拟一个对象。单例模式与单一职责原则有冲突。一个类应该只实现一个逻辑,而不关心它是否是单例的,是不是要单例取决于环境,单例模式把“要单例”和业务逻辑融合在一个类中。
三、单例的使用场景
在一个系统中,要求一个类有且仅有一个对象,如果出现多个对象就会出现“不良反应”,可以采用单例模式,具体的场景如下:要求生成唯一序列号的环境;在整个项目中需要一个共享访问点或共享数据,例如一个Web页面上的计数器,可以不用把每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的;创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源;需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(当然,也可以直接声明为static的方式)
以下是几种基于C#中的单例模式:
/// <summary>
/// 懒汉模式
/// </summary>
public sealed class SingletonIdler
{
private static SingletonIdler instance;
private static readonly object locker=new object();
private SingletonIdler(){}
public static SingletonIdler GetInstance()
{
if (instance==null)
{
lock (locker)
{
instance = new SingletonIdler();
}
}
return instance;
}
}
/// <summary>
/// 饿汉模式
/// </summary>
public sealed class SingleHungry
{
private static SingleHungry instance = new SingleHungry();
private SingleHungry() { }
public static SingleHungry Instance
{
get { return instance; }
}
}
using UnityEngine;
/// <summary>
/// 泛型单例模式
/// </summary>
/// <typeparam name="T"></typeparam>
public class Singleton<T> where T: new()
{
private static T instance;
private readonly static object locker = new object();
public static T Instance
{
get
{
if (instance == null)
{
lock (locker)
{
instance = new T();
}
}
return instance;
}
}
}
unity中实现的通用单例模式:
using UnityEngine;
public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoBehaviour
{
public bool global;
private static readonly object locker = new object();
private static T instance;
public static T Instance
{
get
{
if (ApplicationIsQuitting)
{
if (Debug.isDebugBuild)
{
Debug.LogWarning("[Singleton] Instance '" + typeof(T) +
"' already destroyed on application quit." +
" Won't create again - returning null.");
}
return null;
}
lock (locker)
{
if (instance == null)
{
instance = FindObjectOfType<T>();
if (instance == null)
{
GameObject obj = new GameObject("[Singleton]" + typeof(T));
instance = obj.AddComponent<T>();
}
}
}
return instance;
}
}
void Start()
{
if (global) DontDestroyOnLoad(this.gameObject);
this.OnStart();
}
protected virtual void OnStart()
{
}
protected static bool ApplicationIsQuitting { get; private set; }
public void OnApplicationQuit()
{
ApplicationIsQuitting = true;
}
}
测试代码:
//C#版通用泛型应用代码
public class SingletonExample : Singleton<SingletonExample>
{
public void Test()
{
Debug.Log("singleton test");
}
}
//unity通用泛型应用代码
using UnityEngine;
public class MonoSingletonTest : MonoSingleton<MonoSingletonTest>
{
public void Test()
{
Debug.Log("monoSingleton test");
}
private void Awake()
{
global = true;
}
}
测试结果:
using UnityEngine;
public class SingletonTest : MonoBehaviour
{
private void Start()
{
SingletonExample.Instance.Test();
MonoSingletonTest.Instance.Test();
}
}
理论知识参考《设计模式之禅》