上一篇文章中說到的 manager of managers,其中每個 manager 都是單例的實現,當然也可以使用靜態類實現,但是相比于靜態類的實現,單例的實現更為通用,可以適用大多數情況。
## 如何設計這個單例的模板?
先分析下需求,當設計一個 manager 時候,我們希望整個程序只有一個該 manager 對象實例,一般馬上能想到的實現是這樣的:
```cs
public class XXXManager
{
private static XXXManager instance = null;
private XXXManager
{
// to do ...
}
public static XXXManager()
{
if (instance == null)
{
instance = new XXXManager();
}
return instance;
}
}
```
如果一個游戲需要10個各種各樣的manager,那么以上這些代碼要復制粘貼好多遍。重復的代碼太多!!!想要把重復的代碼抽離出來,怎么辦?答案是引入泛型。實現如下:
```cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace QFramework
{
public abstract class QSingleton<T> where T : QSingleton<T>
{
protected static T instance = null;
protected QSingleton()
{
}
public static T Instance()
{
if (instance == null)
{
// 如何new 一個T???
}
return instance;
}
}
}
```
為了可以被繼承,靜態實例和構造方法都使用protect修飾符。以上的問題很顯而易見,那就是不能new一個泛型(3月9日補充:并不是不能new一個泛型,參考:[new一個泛型的實例,編譯失敗了,為什么?-CSDN論壇-CSDN.NET-中國最大的IT技術社區](http://bbs.csdn.net/topics/390911693)),(4月5日補充:有同學說可以new一個泛型的實例,不過要求改泛型提供了public的構造函數,好吧,這里不用new的原因是,無法顯示調用private的構造函數)。因為泛型本身不是一個類型,那該怎么辦呢?答案是使用反射。實現如下:
```cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
/// <summary>
/// 1.泛型
/// 2.反射
/// 3.抽象類
/// 4.命名空間
/// </summary>
namespace QFramework
{
public abstract class QSingleton<T> where T : QSingleton<T>
{
protected static T instance = null;
protected QSingleton()
{
}
public static T Instance()
{
if (instance == null)
{
// 先獲取所有非public的構造方法
ConstructorInfo[] ctors = typeof(T).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic);
// 從ctors中獲取無參的構造方法
ConstructorInfo ctor = Array.Find(ctors, c => c.GetParameters().Length == 0);
if (ctor == null)
throw new Exception("Non-public ctor() not found!");
// 調用構造方法
instance = ctor.Invoke(null) as T;
}
return instance;
}
}
}
```
以上就是最終實現了。這個實現是在任何C#程序中都是通用的。其測試用例如下所示:
```cs
using QFramework;
// 1.需要繼承QSingleton。
// 2.需要實現非public的構造方法。
public class XXXManager : QSingleton<XXXManager>
{
private XXXManager()
{
// to do ...
}
}
public static void main(string[] args)
{
XXXManager.Instance().xxxyyyzzz();
}
```
## 總結:
這個單例的模板是平時用得比較順手的工具了,其實現是在其他的框架中發現的,拿來直接用了。反射的部分可能會耗一些性能,但是只會執行一次。在 Unity 中可能會需要繼承 MonoBehaviour 的單例,因為很多游戲可能會只創建一個GameObject,用來獲取 MonoBehaviour 的生命周期,這些內容會再下一講中介紹:)。
轉載請注明地址:涼鞋的筆記:[liangxiegame.com](http://liangxiegame.com)
## 更多內容
* QFramework 地址:[https://github.com/liangxiegame/QFramework](https://github.com/liangxiegame/QFramework)
* QQ 交流群:[623597263](http://shang.qq.com/wpa/qunwpa?idkey=706b8eef0fff3fe4be9ce27c8702ad7d8cc1bceabe3b7c0430ec9559b3a9ce66)
* **Unity 進階小班**:
* 主要訓練內容:
* 框架搭建訓練(第一年)
* 跟著案例學 Shader(第一年)
* 副業的孵化(第二年、第三年)
* 權益、授課形式等具體詳情請查看[《小班產品手冊》](https://liangxiegame.com/master/intro):https://liangxiegame.com/master/intro
* 關注公眾號:liangxiegame 獲取第一時間更新通知及更多的免費內容。

- 正文
- Unity 游戲框架搭建 2017(一)概述
- Unity 游戲框架搭建 2017(二)單例的模板
- Unity 游戲框架搭建 2017(三)MonoBehaviour 單例的模板
- Unity 游戲框架搭建 2017(四)簡易有限狀態機
- Unity 游戲框架搭建 2017(五)簡易消息機制
- Unity 游戲框架搭建 2017 (六) 關于框架的一些好文和一些思考
- Unity 游戲框架搭建 2017 (七) 減少加班利器-QApp類
- Unity 游戲框架搭建 2017 (八) 減少加班利器-QLog
- Unity 游戲框架搭建 2017 (九) 減少加班利器-QConsole
- Unity 游戲框架搭建 2017 (十) QFramework v0.0.2小結
- Unity 游戲框架搭建 2017 (十一) 簡易 AssetBundle 打包工具 (一)
- Unity 游戲框架搭建 2017 (十二) 簡易 AssetBundle 打包工具 (二)
- Unity 游戲框架搭建 2017 (十三) 無需繼承的單例的模板
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSingleton (零) QuickStart
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSingleton (一) Singleton 單例實現
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSingleton (二) MonoSingleton單例實現
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSignleton (三) 通過屬性器實現 Singleton
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSingleton (四) 屬性器實現 Mono 單例
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSingleton (五) 優雅地進行GameObject命名
- Unity 游戲框架搭建 2017 (十五) 優雅的 QChain (零)
- Unity 游戲框架搭建 2017 (十六) v0.0.3 架構調整
- Unity 游戲框架搭建 2017 (十七) 靜態擴展GameObject 實現鏈式編程
- Unity 游戲框架搭建 2017 (十八) 靜態擴展 + 泛型實現 transform 的鏈式編程
- Unity 游戲框架搭建 2017 (十九) 簡易對象池
- Unity 游戲框架搭建 2017 (二十) 安全的對象池
- Unity 游戲框架搭建 2017 (二十一) 使用對象池時的一些細節
- Unity 游戲框架搭建 2017 (二十二) 簡易引用計數器
- Unity 游戲框架搭建 2017 (二十三) 重構小工具 Platform
- Unity 游戲框架搭建 2017 (二十四) 小結