UniWb-5- Single

  单例模式实在太常用了,有时各种 manger 各种 tool 都需要使用单例模式。

  但是在 像 unity 这种组件模式的代码结构中,去写单例模式,有时还是会很棘手~~

  那么先开始的开始开始吧~~~

  我愿我是一个愉快的搬运工~

c# 单例模板

当你脑海中想获取一个单例的时候,你手毫不犹豫的就写成这样了,

嗯,我在 winForm 程序都是这样写的,挺好的并没有发生什么问题,连你觉得这样都是对的时候,可能就在为自己的懒惰找借口了~ 好,你问我要不要改,我才不会改了~。。。


public class XXXManager() {
    public static XXXManager instance = new XXXManager();
    
  }
}

这种有什么缺点呢,

1. 程序在一开始的时候就会创建实例对象,浪费内存

2. 这种并不能算做单例模式,因为它任然可以再次实例化

 

于是我们改进下它,


public class XXXManager() {
    public static XXXManager mInstance = null;
    
    public static Instance 
    {
      get
       {
          if(mInstance == null) mInstance = new XXXManager();
          return mInstance; 
       }
    }
  }
}

现在我们更进了一步,起码内存是在我需要这个实例的时候再去创建它,避免内存浪费。

但是我们觉得这还是不够的,并且我们觉得还是太麻烦了,假如这样的单例太多了,那么每一个都这样写,那么这样并不太好。

using System;  
using System.Collections.Generic;  
using System.Text;  
using System.Reflection;


public abstract class Singleton<T> where T : Singleton<T>
{
    protected static T instance = null;

    protected Singleton()
    {
    }

    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;
    }
}

 

 

我们这样有一个 抽象模板单例类  Singleton ,用泛型去区分类型,注意这里我们的构造函数是 protected 类型的,也就是说我不能在其它地方去创建它的实例,因为它实在没有构造函数了。

但是我们要创建实例怎么办? 好在 c# 有反射,去创建实例。这样我们一个比较好的单例模式就基本成型了。


MonoBehaviour 单例模板

搬运中~~~~~~

如何设计接收MonoBehaviour生命周期的单例的模板?

如何设计?
先分析下需求:
  1.约束脚本实例对象的个数。
  2.约束GameObject的个数。
  3.接收MonoBehaviour生命周期。
  4.销毁单例和对应的GameObject。

using UnityEngine;

/// <summary>
/// 需要使用Unity生命周期的单例模式
/// </summary>
 
public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
{
    protected static T instance = null;

    public static T Instance()
    {
        if (instance == null)
        {
            instance = FindObjectOfType<T>();

            if (FindObjectsOfType<T>().Length > 1)
            {
                return instance;
            }

            if (instance == null)
            {
                string instanceName = typeof(T).Name;
                GameObject instanceGO = GameObject.Find(instanceName);

                if (instanceGO == null)
                    instanceGO = new GameObject(instanceName);
                instance = instanceGO.AddComponent<T>();
                DontDestroyOnLoad(instanceGO);  //保证实例不会被释放
                
            }
            else
            {
                
            }
        }

        return instance;
    }


    protected virtual void OnDestroy()
    {
        instance = null;
      }
  }

 

这里会首先判断挂载实例的数目, 永远只需要一个实例,然后 DontDestroyOnLoad, 确保它不会被销毁。

 

 public abstract class MonoSingleton<T> : MonoBehaviour, ISingleton where T : MonoSingleton<T>
    {
        protected static T mInstance = null;

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

                return mInstance;
            }
        }

        public virtual void OnSingletonInit()
        {
        }

        public virtual void Dispose()
        {
            if (MonoSingletonCreator.IsUnitTestMode)
            {
                var curTrans = transform;
                do
                {
                    var parent = curTrans.parent;
                    DestroyImmediate(curTrans.gameObject);
                    curTrans = parent;
                } while (curTrans != null);

                mInstance = null;
            }
            else
            {
                Destroy(gameObject);
            }
        }

        protected virtual void OnDestroy()
        {
            mInstance = null;
        }
    }
 public static class MonoSingletonCreator
    {
        public static bool IsUnitTestMode { get; set; }

        public static T CreateMonoSingleton<T>() where T : MonoBehaviour, ISingleton
        {
            T instance = null;

            if (!IsUnitTestMode && !Application.isPlaying) return instance;
            instance = Object.FindObjectOfType<T>();

            if (instance != null)
            {
                instance.OnSingletonInit();
                return instance;
            }

            MemberInfo info = typeof(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;
            }

            if (instance == null)
            {
                var obj = new GameObject(typeof(T).Name);
                if (!IsUnitTestMode)
                    Object.DontDestroyOnLoad(obj);
                instance = obj.AddComponent<T>();
            }

            instance.OnSingletonInit();
            return instance;
        }

        private static T CreateComponentOnGameObject<T>(string path, bool dontDestroy) where T : MonoBehaviour
        {
            var obj = FindGameObject(path, true, dontDestroy);
            if (obj == null)
            {
                obj = new GameObject("Singleton of " + typeof(T).Name);
                if (dontDestroy && !IsUnitTestMode)
                {
                    Object.DontDestroyOnLoad(obj);
                }
            }

            return obj.AddComponent<T>();
        }

        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);
        }

        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);
        }
    }

在这里 UniWb 里 封装了  MonoSingletonCreator.CreateMonoSingleton 这个方法,让创建这样的实例会很方便,但原理都是相同的

 

这样一来我们单例才算真正的能很好的使用了~~~~

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值