单例模式 花里胡哨单例

保证一个类只有一个实例,并且提供了访问该实例的全局访问点。

尽管它的意图是好的,GoF描述的单例模式通常弊大于利。 他们强调应该谨慎使用这个模式,但在游戏业界的口口相传中,这一提示经常被无视了。

由于单例只有被使用的时候才会创建实例,不使用则不会被创建。所以节约内存和CPU循环总是好的,但是就像其他模式一样,在不合适的地方使用单例模式就好像用夹板处理子弹伤口。 由于它被滥用得太严重了,所以请适当在合适的地方使用。(QAQ记得开始出来工作疯狂单例狂)

 

先来看一个正常单例

​
   public class TestSingle
    {
        protected static TestSingle instance;
        public static TestSingle Instance
        {
            get
            {
                if (instance == null)
                    instance = new TestSingle();
                return instance;
            }
        }

        public void Debug()
        {
            Console.WriteLine("TestSingleton");
        }

        public void Dispose()
        {
            instance = null;
        }
    }

一个静态的全局变量,当为空的时候创建一个,保证全局就一个

但是当整个工程里有大量单例类的时候,需要每个都写这样重复代码就很操蛋了。当然你说你公司是按照代码量来绩效考核那准没问题了- -,所以此时需要引入泛型单例。

   public class SingletonComponent<T>where T : new()
    {
        protected static T instance;

        public static T Instance
        {
            get
            {
                if (instance == null)
                    instance = new T();
                return instance;
            }
        }
    }

此时泛型单例已经解决了重复劳动的活了,模板化。

但是此时,如果一个类是需要继承单例并且还要继承其他类时候,在多继承的时候,此时泛型单例并不满足(至少在C#是不允许的)。比如这种情况:

需求继承BaseTest时候在继承Singleton,C#是不允许这么做的,写了编译的时候直接会报错

public class TTestSingleton:BaseTest
    {

        private TTestSingleton()
        {
            Console.WriteLine("TTestSingleton Is New");
        }

        public void Debug()
        {
            Console.WriteLine("TTestSingleton");
        }

 
    }

此时解决办法是:如果让单例充当属性,就能很完美解决这个问题

 


 public class SingletonComponent<T>where T:class
    {
        protected static T instance;
        protected SingletonComponent()
        {
        }

        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    //获取私有构造函数
                    ConstructorInfo[] ctors = typeof(T).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic);
                    //无参数构造函数
                    ConstructorInfo ctor = Array.Find(ctors, c => c.GetParameters().Length == 0);
                    if (ctor == null)
                        throw new Exception("Not Find Non-Public ctors()");

                    instance = ctor.Invoke(null) as T;
                }
                return instance;
            }
 
        }

        public void Dispose()
        {
            instance = null;
        }

    }


    public class TTestSingleton:BaseTest
    {

        private TTestSingleton()
        {
            Console.WriteLine("TTestSingleton Is New");
        }

        public void Debug()
        {
            Console.WriteLine("TTestSingleton");
        }

        public static TTestSingleton Instance
        {
            get
            {
                return SingletonComponent<TTestSingleton>.Instance;
            }
        }

        
    }

   public class BaseTest
   {
      public virtual void TEST()
      {
        Console.WriteLine("TEST");
       }
    }
​



​

TTsingleton就能在继承其他Base类的时候也能充当单例模块。

为了可以被继承,静态实例和构造方法都使用protect修饰符

此时问题是不能New一个泛型,(并不是不能New一个泛型出来)如果New的话不能显示调用私有构造函数,但是泛型如果使用New()进行约束,就能New了,

但是其实最终也是进行了t = System.Activator.CreateInstance<T>();这操作

所以直接使用反射来进行构造。

 

来让看下在UnityMono中单例是如何实现:

Mono中使用单例 ,也是保证全局唯一,并且有检查唯一性方法

这里单例模板也是使用了反射,利用特性进行打上标签,进行生产的时候可以根据标签来生成

ISingleton接口可以让单例模板进行更多操作,当前写了一个OnInitSingle初始化办法

 

public abstract class MonoSingletonComponent<T>:MonoBehaviour,ISingleton where T:MonoSingletonComponent<T>
{
    protected static T instance;
   
    public static T Instance
    {
        get
        {
            instance = FindObjectOfType<T>();
            if (FindObjectsOfType<T>().Length > 1)
                throw new System.Exception("Mono Type" + typeof(T).Name + "More Than One");
            if (instance == null)
            {
                string typeName = string.Empty;
                SingletonPathAttribute attribute = typeof(T).GetCustomAttribute<SingletonPathAttribute>();

                if (attribute == null)
                    typeName = typeof(T).Name;    
                else
                    typeName = attribute.MPathInHierarchyName;

                GameObject[] objs = FindSingletonPathAttributeGameObject.Find(typeName);
                //最后一个节点进行添加脚本
                instance = objs[0].AddComponent<T>();
                //DontDestroyOnLoad 如果是子节点会给警告,需要进行父节点DontDestroyOnLoad
                DontDestroyOnLoad(objs[1].gameObject);
            }
            else
            {
                Debug.Log(string.Format("{0} is already exit", typeof(T).Name));
            }
            return instance;
        }

    }

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

    public virtual  void OnInitSingleton()
    {
       
    }

    public virtual void Dispose()
    {
        UnityEngine.Object.DestroyImmediate(instance.gameObject);
    }
}


public interface ISingleton
{
    void OnInitSingleton();
}


public class SingletonPathAttribute : System.Attribute
{
    private string mPathInHierarchyName;

    public SingletonPathAttribute(string _pathName)
    {
        mPathInHierarchyName = _pathName;
    }

    public string MPathInHierarchyName { get => mPathInHierarchyName;}
}

public class FindSingletonPathAttributeGameObject
{
    public static GameObject[] Find(string path)
    {
        GameObject[] objs = new GameObject[2];
        string[]pathArray=path.Split('/');
        if (pathArray.Length <= 0)
        {
            objs[0] = GameObject.Find(path);
            objs[1] = objs[0];
        }
        else
        {
            for (int i = 0; i < pathArray.Length; i++)
            {
                if (objs[0] == null)
                    objs[0] = GameObject.Find(pathArray[i]);
                else
                    objs[0] = objs[0].transform.Find(pathArray[i]).gameObject;

                if (i == 0)
                    objs[1] = objs[0];
            }
        }

        if (objs[0] == null)
        {
            if (pathArray.Length <= 0)
            {
                objs[0] = new GameObject(path);
                objs[1]= objs[0];
            }
            else
            {
                for (int i = 0; i < pathArray.Length; i++)
                {
                    if (objs[0] == null)
                    {
                        objs[0] = new GameObject(pathArray[i]);
                    }   
                    else
                    {
                        GameObject _newObj= new GameObject(pathArray[i]);
                        _newObj.transform.parent = objs[0].transform;
                        objs[0] = _newObj;
                    }
                    objs[0].name = pathArray[i];

                    if (i == 0)
                        objs[1] = objs[0];
                }
            }
           
        }

        return objs;
    }
}

 

最后是生成的例子

   [SingletonPathAttribute("[Test]/MonoSingle")]
    public class TestMonoSingletonComponent:MonoSingletonComponent<TestMonoSingletonComponent>
    {
        public override void OnInitSingleton()
        {
            base.OnInitSingleton();
            Debug.Log("TestMonoSingletonComponent OnInit");
        }
    }

 

 

上述代码也是借鉴(chao)别人进行完善,努力奋斗

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值