上一篇文章中說到的manager of managers,其中每個manager都是單例的實現,當然也可以使用靜態類實現,但是相比于靜態類的實現,單例的實現更為通用,可以適用大多數情況。
如何設計這個單例的模板?
先分析下需求,當設計一個manager時候,我們希望整個程序只有一個該manager對象實例,一般馬上能想到的實現是這樣的:
publicclassXXXManager {
privatestaticXXXManager instance =null;
privateXXXManager {
// to do ...
}
publicstaticXXXManager() {
if(instance ==null)
{
instance =newXXXManager();
}
returninstance;
}
}
如果一個游戲需要10個各種各樣的manager,那么以上這些代碼要復制粘貼好多遍。重復的代碼太多!!!想要把重復的代碼抽離出來,怎么辦?答案是引入泛型。實現如下:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
usingSystem.Reflection;
namespaceQFramework {
publicabstractclassQSingleton where T : QSingleton
{
protectedstaticT instance =null;
protectedQSingleton()
{
}
publicstaticT Instance()
{
if(instance ==null)
{
// 如何new 一個T???
}
returninstance;
}
}
}
為了可以被繼承,靜態實例和構造方法都使用protect修飾符。以上的問題很顯而易見,那就是不能new一個泛型(3月9日補充:并不是不能new一個泛型,參考:[new一個泛型的實例,編譯失敗了,為什么?-CSDN論壇-CSDN.NET-中國最大的IT技術社區](http://bbs.csdn.net/topics/390911693)),(4月5日補充:有同學說可以new一個泛型的實例,不過要求改泛型提供了public的構造函數,好吧,這里不用new的原因是,無法顯示調用private的構造函數)。因為泛型本身不是一個類型,那該怎么辦呢?答案是使用反射。實現如下:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
usingSystem.Reflection;
///
/// 1.泛型
/// 2.反射
/// 3.抽象類
/// 4.命名空間
///
namespaceQFramework {
publicabstractclassQSingleton where T : QSingleton
{
protectedstaticT instance =null;
protectedQSingleton()
{
}
publicstaticT 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)
thrownewException("Non-public ctor() not found!");
// 調用構造方法
instance = ctor.Invoke(null)asT;
}
returninstance;
}
}
}
以上就是最終實現了。這個實現是在任何C#程序中都是通用的。其測試用例如下所示:
usingQFramework;
// 1.需要繼承QSingleton。
// 2.需要實現非public的構造方法。
publicclassXXXManager : QSingleton {
privateXXXManager() {
// to do ...
}
}
publicstaticvoidmain(string[] args)
{
XXXManager.Instance().xxxyyyzzz();
}
總結
這個單例的模板是平時用得比較順手的工具了,其實現是在其他的框架中發現的,拿來直接用了。反射的部分可能會耗一些性能,但是只會執行一次。在Unity中可能會需要繼承MonoBehaviour的單例,因為很多游戲可能會只創建一個GameObject,用來獲取MonoBehaviour的生命周期,這些內容會再下一講中介紹:)
附:[我的框架地址](https://github.com/liangxiegame/QFramework)
轉載請注明地址:[涼鞋的筆記](http://liangxiegame.com/)