前提
- 继承MonoBehaviour的脚本不能new
- 继承MonoBehaviour的脚本一定得依附在GameObject上
实现挂载式的单例模式基类
挂载式 继承Mono的单例模式基类
csharp
/// <summary>
/// 挂载式 继承Mono的单例模式基类
/// </summary>
/// <typeparam name="T"></typeparam>
public class SingletonMono<T>: MonoBehaviour where T:MonoBehaviour
{
private static T instance;
public static T Instance
{
get
{
return instance;
}
}
// 子类可能要重写Awake函数,所以设置为虚函数
protected virtual void Awake()
{
instance = this as T;
}
}
TestMgr2继承单例模式的基类,然后把脚本挂在到游戏对象上去,才能在Awake赋值
csharp
public class TestMgr2 : SingletonMono<TestMgr2>
{
private int i;
protected override void Awake()
{
// 重写Awake时候,这里不能省略
base.Awake();
i = 0;
}
public void TestLog()
{
print("TestMgr2" + i);
}
}
测试
csharp
public class Main : MonoBehaviour
{
private void Start()
{
TestMgr2.Instance.TestLog();
}
}
缺点
因为很容易被破坏单例模式的唯一性
1.挂载多个脚本
2.切换场景回来时,由于场景放置了挂载脚本的对象,回到该场景时 又会有一个该单例模式对象
3.还可以通过代码动态的添加多个该脚本 也会破坏唯一性
修改Awake
csharp
/// <summary>
/// 挂载式 继承Mono的单例模式基类
/// </summary>
/// <typeparam name="T"></typeparam>
public class SingletonMono<T>: MonoBehaviour where T:MonoBehaviour
{
private static T instance;
public static T Instance
{
get
{
return instance;
}
}
// 子类可能要重写Awake函数,所以设置为虚函数
protected virtual void Awake()
{
//已经存在一个对应的单例模式对象了 不需要在有一个了
if(instance != null)
{
// 只会移除脚本
Destroy(this);
return;
}
instance = this as T;
//我们挂载继承该单例模式基类的脚本后 依附的对象过场景时就不会被移除了
//就可以保证在游戏的整个生命周期中都存在
DontDestroyOnLoad(this.gameObject);
}
}
实现自动挂载式的单例模式基类
创建单例模式基类SingletonAutoMono,实现动态挂载脚本
csharp
/// <summary>
/// 自动挂载式的 继承Mono的单例模式基类
/// 推荐使用
/// 无需手动挂载 无需动态添加 无需关心切场景带来的问题
/// </summary>
/// <typeparam name="T"></typeparam>
public class SingletonAutoMono<T> : MonoBehaviour where T:MonoBehaviour
{
private static T instance;
public static T Instance
{
get
{
if(instance == null)
{
//动态创建 动态挂载
//在场景上创建空物体
GameObject obj = new GameObject();
//得到T脚本的类名 为对象改名 这样再编辑器中可以明确的看到该
//单例模式脚本对象依附的GameObject
obj.name = typeof(T).ToString();
//动态挂载对应的 单例模式脚本
instance = obj.AddComponent<T>();
//过场景时不移除对象 保证它在整个游戏生命周期中都存在
DontDestroyOnLoad(obj);
}
return instance;
}
}
}
Test2Mgr2继承单例模式基类
csharp
public class Test2Mgr2 : SingletonAutoMono<Test2Mgr2>
{
public void TestLog()
{
print("Test2Mgr2");
}
}
测试
csharp
public class Main : MonoBehaviour
{
private void Start()
{
Test2Mgr2.Instance.TestLog();
}
}
潜在的安全问题
- 构造函数问题:
继承MonoBehaviour的函数,不能new,所以不用担心公共构造函数 - 多线程问题:
Unity主线程中相关内容,不允许其他线程直接调用,很少有这样的需求,所以也不用太担心 - 重复挂载问题:
- 手动重复挂载
- 代码重复添加
需要人为干涉,定规则,或者通过代码逻辑强制处理