Singleton

ISingleton

先将重点的ISingleton接口绘制成UML

代码:

1
2
3
4
5
6
7
8
9
10
/// <summary>
/// 单例接口
/// </summary>
public interface ISingleton
{
/// <summary>
/// 单例初始化(继承当前接口的类都需要实现该方法)
/// </summary>
void OnSingletonInit();
}

ISingleton

此图是类图,接口的UML图不是这样的

SingletonCreator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/// <summary>
/// 普通单例创建类
/// </summary>
internal static class SingletonCreator
{
static T CreateNonPublicConstructorObject<T>() where T : class
{
var type = typeof(T);
// 获取私有构造函数
var constructorInfos = type.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic);

// 获取无参构造函数
var ctor = Array.Find(constructorInfos, c => c.GetParameters().Length == 0);

if (ctor == null)
{
throw new Exception("Non-Public Constructor() not found! in " + type);
}

return ctor.Invoke(null) as T;
}

public static T CreateSingleton<T>() where T : class, ISingleton
{
var type = typeof(T);
var monoBehaviourType = typeof(MonoBehaviour);

if (monoBehaviourType.IsAssignableFrom(type))
{
return CreateMonoSingleton<T>();
}
else
{
var instance = CreateNonPublicConstructorObject<T>();
instance.OnSingletonInit();
return instance;
}
}
//...
}

SingletonCreator的职责是,通过反射来确定一个普通单例类是否有私有构造函数,并在其私有构造中获取无参构造,使用这个无参构造实例化普通单例类

SingletonCreator

Singleton<T>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public abstract class Singleton<T> : ISingleton where T : Singleton<T>
{
/// <summary>
/// 静态实例
/// </summary>
protected static T mInstance;

/// <summary>
/// 标签锁:确保当一个线程位于代码的临界区时,另一个线程不进入临界区。
/// 如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放
/// </summary>
static object mLock = new object();

/// <summary>
/// 静态属性
/// </summary>
public static T Instance
{
get
{
lock (mLock)
{
if (mInstance == null)
{
mInstance = SingletonCreator.CreateSingleton<T>();
}
}

return mInstance;
}
}

/// <summary>
/// 资源释放
/// </summary>
public virtual void Dispose()
{
mInstance = null;
}

/// <summary>
/// 单例初始化方法
/// </summary>
public virtual void OnSingletonInit()
{
}
}

目前完整的UML类图

下划线表示静态的。

MonoSingleton

CreateMonoSingleton

首先我们查看一下SingletonCreator里面创建MonoSingleton的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
internal static class SingletonCreator
{
//...
public static T CreateMonoSingleton<T>() where T : class, ISingleton
{
T instance = null;
var type = typeof(T);

//判断T实例存在的条件是否满足
if (!IsUnitTestMode && !Application.isPlaying)
return instance;

//判断当前场景中是否存在T实例
instance = UnityEngine.Object.FindObjectOfType(type) as T;
if (instance != null)
{
instance.OnSingletonInit();
return instance;
}

//MemberInfo:获取有关成员属性的信息并提供对成员元数据的访问
MemberInfo info = typeof(T);
//获取T类型 自定义属性,并找到相关路径属性,利用该属性创建T实例
var attributes = info.GetCustomAttributes(true);
foreach (var atribute in attributes)
{
var defineAttri = atribute as MonoSingletonPath;
if (defineAttri == null)
{
continue;
}

instance = CreateComponentOnGameObject<T>(defineAttri.PathInHierarchy, true);//使用这个方法应用特性
break;
}

//如果还是无法找到instance 则主动去创建同名Obj 并挂载相关脚本 组件
if (instance == null)
{
var obj = new GameObject(typeof(T).Name);
if (!IsUnitTestMode)
UnityEngine.Object.DontDestroyOnLoad(obj);
instance = obj.AddComponent(typeof(T)) as T;
}

instance.OnSingletonInit();
return instance;
}
//...
}

对应的UML图如下(简化)

MonoSingletonCreator

MonoSingleton<T>

我们看一下MonoSingleton<T>泛型类的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/// <summary>
/// 静态类:MonoBehaviour类的单例
/// 泛型类:Where约束表示T类型必须继承MonoSingleton<T>
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class MonoSingleton<T> : MonoBehaviour, ISingleton where T : MonoSingleton<T>
{
/// <summary>
/// 静态实例
/// </summary>
protected static T mInstance;

/// <summary>
/// 静态属性:封装相关实例对象
/// </summary>
public static T Instance
{
get
{
if (mInstance == null && !mOnApplicationQuit)
{
mInstance = SingletonCreator.CreateMonoSingleton<T>();
}

return mInstance;
}
}

/// <summary>
/// 实现接口的单例初始化
/// </summary>
public virtual void OnSingletonInit()
{
}

/// <summary>
/// 资源释放
/// </summary>
public virtual void Dispose()
{
if (SingletonCreator.IsUnitTestMode)
{
var curTrans = transform;
do
{
var parent = curTrans.parent;
DestroyImmediate(curTrans.gameObject);
curTrans = parent;
} while (curTrans != null);

mInstance = null;
}
else
{
//我们在下方监听了OnDestroy,在那里已经将mInstance置空了,所以这里直接Destroy即可
Destroy(gameObject);
}
}

/// <summary>
/// 当前应用程序是否结束 标签
/// </summary>
protected static bool mOnApplicationQuit = false;

/// <summary>
/// 应用程序退出:释放当前对象并销毁相关GameObject
/// </summary>
protected virtual void OnApplicationQuit()
{
mOnApplicationQuit = true;
if (mInstance == null) return;
Destroy(mInstance.gameObject);
mInstance = null;
}

/// <summary>
/// 释放当前对象
/// </summary>
protected virtual void OnDestroy()
{
mInstance = null;
}

/// <summary>
/// 判断当前应用程序是否退出
/// </summary>
public static bool IsApplicationQuit
{
get { return mOnApplicationQuit; }
}
}

MonoSingleton除了要考虑单例的实现之外,还需要实现一些容错处理,以及一些声明周期查询,比如IsApplicationQuit等。

UML图如下:

两种单例的UML

SingletonProperty和MonoSingletonProperty

我们在上一节介绍过这两个类的意义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/// <summary>
/// 属性单例类
/// </summary>
/// <typeparam name="T"></typeparam>
public static class SingletonProperty<T> where T : class, ISingleton
{
/// <summary>
/// 静态实例
/// </summary>
private static T mInstance;

/// <summary>
/// 标签锁
/// </summary>
private static readonly object mLock = new object();

/// <summary>
/// 静态属性
/// </summary>
public static T Instance
{
get
{
lock (mLock)
{
if (mInstance == null)
{
mInstance = SingletonCreator.CreateSingleton<T>();
}
}

return mInstance;
}
}

/// <summary>
/// 资源释放
/// </summary>
public static void Dispose()
{
mInstance = null;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/// <summary>
/// 继承Mono的属性单例?
/// </summary>
/// <typeparam name="T"></typeparam>
public static class MonoSingletonProperty<T> where T : MonoBehaviour, ISingleton
{
private static T mInstance;

public static T Instance
{
get
{
if (null == mInstance)
{
mInstance = SingletonCreator.CreateMonoSingleton<T>();
}

return mInstance;
}
}

public static void Dispose()
{
if (SingletonCreator.IsUnitTestMode)
{
UnityEngine.Object.DestroyImmediate(mInstance.gameObject);
}
else
{
UnityEngine.Object.Destroy(mInstance.gameObject);
}

mInstance = null;
}
}

现在的UML图如下

四种创建单例的UML

MonoSingletonPath特性

MonoSingletonPath特性能够让我们创建的Mono单例按照特性内指定的Hierarchy路径整理好

我们先看一下自定义特性部分的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/// <summary>
/// MonoSingleton路径
/// </summary>
[AttributeUsage(AttributeTargets.Class)] //这个特性只能标记在Class上
public class MonoSingletonPath : Attribute
{
private string mPathInHierarchy;

public MonoSingletonPath(string pathInHierarchy)
{
mPathInHierarchy = pathInHierarchy;
}

public string PathInHierarchy
{
get { return mPathInHierarchy; }
}
}

我们在SingletonCreatorCreateMonoSingleton方法中通过反射获取应用了这个特性的Mono单例和具体的路径信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
internal static class SingletonCreator
{
//...
/// <summary>
/// 查找Obj(一个嵌套查找Obj的过程)
/// </summary>
/// <param name="root">父节点</param>
/// <param name="subPath">拆分后的路径节点</param>
/// <param name="index">下标</param>
/// <param name="build">true</param>
/// <param name="dontDestroy">不要销毁 标签</param>
/// <returns></returns>
private static GameObject FindGameObject(GameObject root, string[] subPath, int index, bool build,
bool dontDestroy)
{
GameObject client = null;

if (root == null)
{
client = GameObject.Find(subPath[index]);
}
else
{
var child = root.transform.Find(subPath[index]);
if (child != null)
{
client = child.gameObject;
}
}

if (client == null)
{
if (build)
{
client = new GameObject(subPath[index]);
if (root != null)
{
client.transform.SetParent(root.transform);
}

if (dontDestroy && index == 0 && !IsUnitTestMode)
{
GameObject.DontDestroyOnLoad(client);
}
}
}

if (client == null)
{
return null;
}

return ++index == subPath.Length ? client : FindGameObject(client, subPath, index, build, dontDestroy);
}

public static T CreateMonoSingleton<T>() where T : class, ISingleton
{
//...
//MemberInfo:获取有关成员属性的信息并提供对成员元数据的访问
MemberInfo info = typeof(T);
//获取T类型 自定义属性,并找到相关路径属性,利用该属性创建T实例
var attributes = info.GetCustomAttributes(true);
foreach (var atribute in attributes)
{
var defineAttri = atribute as MonoSingletonPath;
if (defineAttri == null)
{
continue;
}

instance = CreateComponentOnGameObject<T>(defineAttri.PathInHierarchy, true);//使用这个方法应用特性
break;
}

//...
}

/// <summary>
/// 在GameObject上创建T组件(脚本)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="path">路径(应该就是Hierarchy下的树结构路径)</param>
/// <param name="dontDestroy">不要销毁 标签</param>
/// <returns></returns>
private static T CreateComponentOnGameObject<T>(string path, bool dontDestroy) where T : class
{
var obj = FindGameObject(path, true, dontDestroy);
if (obj == null)
{
obj = new GameObject("Singleton of " + typeof(T).Name);
if (dontDestroy && !IsUnitTestMode)
{
UnityEngine.Object.DontDestroyOnLoad(obj);
}
}

return obj.AddComponent(typeof(T)) as T;
}

/// <summary>
/// 查找Obj(对于路径 进行拆分)
/// </summary>
/// <param name="path">路径</param>
/// <param name="build">true</param>
/// <param name="dontDestroy">不要销毁 标签</param>
/// <returns></returns>
private static GameObject FindGameObject(string path, bool build, bool dontDestroy)
{
if (string.IsNullOrEmpty(path))
{
return null;
}

var subPath = path.Split('/');
if (subPath == null || subPath.Length == 0)
{
return null;
}

return FindGameObject(null, subPath, 0, build, dontDestroy);
}
}

MonoSingletonPath示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using UnityEngine;
using QFramework;

namespace FrameworkDesign
{
public class MonoSingletonExample : MonoBehaviour
{
[MonoSingletonPath("[Logic]/GameManager")]
public class GameManager : MonoSingleton<GameManger>{}
[MonoSingletonPath("[Framework]/ResManager")]
public class ResManager : MonoSingleton<ResManager>{}
[MonoSingletonPath("[Framework]/UIManager")]
public class UIManager : MonoSingleton<UIManager>{}

[MonoSingletonPath("[Framework]/SoundManager")]
public class SoundManager : MonoSingleton<SoundManager>{}
[MonoSingletonPath("[Logic]/ConfigManager")]
public class ConfigManager : MonoSingleton<ConfigManager>{}
[MonoSingletonPath("[Logic]/BattleManager")]
public class BattleManager : MonoSingleton<BattleManager>{}
[MonoSingletonPath("[Framework]/NetworkManager")]
public class NetworkManager : MonoSingleton<NetworkManager>{}

void Start()
{
var gameMgr = GameManager.Instance;
var resMgr = ResManager.Instance;
var uiMgr = UIManager.Instance;
var soundMgr = SoundManager.Instance;
var configMgr = ConfigManager.Instance;
var buttleMgr = BattleManager.Instance;
var networkMgr = NetworkManager.Instance;
}
}
}

最终的UML图

SingletonKit图