单例模式基类

目录

简单的单例模式

继承Mono类的单例模式

优化的继承Mono类的单例模式

总结


简单的单例模式

首先我们来写一个单例类,代码如下:

public class GameManager
    {
        private static GameManager instance;

        public static GameManager Getinstance()
        {
            if (instance == null)
                instance = new GameManager();
            return instance;
        }
    }

有了这个类之后呢,我们要再外面创建一个instance的时候,其实就在外部通过这个类点一个Get方法就可以了,GameMandger.Getinstance(),但是这样一个一个写就会有很多重复的代码,比如你要创建另外一个单例的对象,你又得写一个类,代码和上面一样,只是类的名字换了,所以,我们就有了单例模式的基类,这里我们用到了泛型的知识,具体代码如下:

public class BaseManager<T> where T:new()
{
    private static T instance;

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

因为我们的泛型T传进去的是一个类对象,所以肯定有一个无参构造函数,我们给泛型加一个约束where T:new(),这个T必须拥有一个无参构造函数才能传进来。这样我们只要让我们想拥有单例模式的类继承BaseManager类就可以了。

public class GameManager : BaseManager<GameManager>
{

}

这样我们通过GameManager同样可以点出GetInstance这个方法。

扫描二维码关注公众号,回复: 14875831 查看本文章

继承Mono类的单例模式

接下来就是继承Mono类的单例模式,因为我们继承Mone的时候,我们的对象不是由我们new出来的,继承Mone的对象是在我们挂载到一个Object上,或者我们用api,AddComponent去加脚本,然后U3D内部帮我们把它实例化的,所以我们可以在Awake函数(有点类似于构造函数)里面让我们的instance直接等于它自己,当有Awake函数运行时,说明有对象使用了这个脚本,就相当于判了空。

public class NewBehaviourScript : MonoBehaviour
{
    private static NewBehaviourScript instance;

    public static NewBehaviourScript GetInsttance()
    {
        return instance;
    }

    private void Awake()
    {
        instance = this;
    }
}

同样的,我们要将这个继承Mono的单例写成泛型模式的基类:

public class SingletonMono<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T instance;

    public static T GetInstance()
    {
        return instance;
    }

    protected virtual void Awake()
    {
        instance = this as T;
    }
}

这里我们需要把this李氏转换发把他转成T类型也就是我们的泛型,然后给Mono一个约束,约束。所以我们现在就可以直接用了:

public class NewBehaviourScript : SingletonMono<NewBehaviourScript>
{
     base.Awake();
}

当然因为我们的子类里也有Awake函数,为了预防子类重写它,我们应该把他变成应该虚函数,这样子类重写就不会把父类顶替掉了。

优化的继承Mono类的单例模式

因为如果我们将脚本挂载到多个Object上的时候,就破坏了我们的单例模式,因为它只会指向我们最后挂载的那个Object。我们来改良他。

public class SingletonAutoMono<T> : MonoBehaviour where T:MonoBehaviour
{
    private static T instance;

    public static T GetInstance()
    {
        if(instance == null)
        {
            GameObject obj = new GameObject();
            //设置对象名称为脚本名
            obj.name = typeof(T).ToString();

            //让这个单例对象过场景不被移除
            DontDestroyOnLoad(obj);
            instance = obj.AddComponent<T>();
        }
        return instance;
    }
}

这样写,就当我们要使用单例模式的时候,直接用我们写好的单例类点一个GetInstance的方法,就能创建一个新的空对象,并把他起名为我们的脚本名称。这样可以防止我们多挂。

总结

继不继承Mono类的这个两种单例模式就讲完了,那么一般来说多数会使用前一种,就就是不继承,因为在切换场景的时候,继承的很容易会被清空,而不继承的一般你不手动去清空是不会被清空的。除非你一定得用Mono类里面的东西。

猜你喜欢

转载自blog.csdn.net/weixin_47042152/article/details/126224939
今日推荐