目录
简单的单例模式
首先我们来写一个单例类,代码如下:
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这个方法。
继承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类里面的东西。