通过从不同角度查看问题可以避免单身滥用。假设一个程序只需要一个类的一个实例,并且应用程序在启动时配置该类:那为什么该类本身就应该成为一个单例?由于程序需要这种行为,因此程序承担这一责任是合乎逻辑的。此程序应该是单例,而不是组件。然后,程序使组件的实例可用于任何特定于应用程序的代码。当程序使用多个这样的组件时,它可以将它们聚合到我们称之为工具箱的组件中。
简而言之,程序的工具箱是一个单例,负责配置自身或允许程序的启动机制进行配置。工具箱单例的一般模式如下图所示
工具箱本身是一个单例,它管理各个组件实例的生存期。 应用程序要么配置它,要么在方法初始化中请求配置应用程序的信息。 现在应用程序可以决定它需要多少个类的实例。 这些决策的更改可能会影响特定于应用程序的代码,但不会重用基础结构级别的代码。 此外,测试基础结构代码要容易得多,因为这些类不依赖于任何应用程序可能选择使用它们的方式。
【Unity环境中实现】
public class Singleton<T> : MonoBehaviour where T : Component {
private static T _instance;
private static Object _lock = new Object();
public static T Instance {
get {
if (applicationIsQuitting) {
Debug.LogWarning("[Singleton] 单例 '" + typeof(T) +
"' 应用已经退出." +
" 无法再次创建Singleton - 返回值为 null.");
return null;
}
lock (_lock) {
if (_instance == null) {
_instance = FindObjectOfType<T>();
if (FindObjectsOfType<T>().Length > 1) {
Debug.LogError("[Singleton] 发生了一些错误 " +
" - 场景中存在不止一个Singleton!" +
" 重新打开场景并修复他.");
return _instance;
}
if (_instance == null)
{
GameObject singleton = new GameObject();
_instance = singleton.AddComponent<T>();
singleton.name = "singleton" + typeof(T).ToString();
DontDestroyOnLoad(singleton);
Debug.Log("[Singleton] 实例化了一个 " + typeof(T) +
" 类型,他需要一直存在在场景当中,所以 '" + singleton +
"' 将不会被销毁.");
}
else {
Debug.Log("[Singleton] 已使用了Singleton创建过了: " +
_instance.gameObject.name);
}
}
return _instance;
}
}
}
private static bool applicationIsQuitting = false;
public void OnDestroy()
{
applicationIsQuitting = true;
}
}
public class Toolbox : Singleton<Toolbox> {
public void PrintSelf()
{
print("PrintSelf");
}
}
public class MyClass : MonoBehaviour {
void Awake () {
Toolbox toolbox = Toolbox.Instance;
toolbox.PrintSelf();
Collider collider = Toolbox.Instance.gameObject.AddComponent<BoxCollider>();
Debug.Log(collider.name);
}
}