一、简介
当谈到Unity游戏开发时,设计模式是一个非常重要的主题,其中之一就是单例模式。单例模式是一种创建模式,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例。在Unity中,单例模式经常用于管理全局游戏状态、资源管理、对象池等方面。在本文中,我们将探讨Unity中如何实现单例模式以及其优势。
二、单例模式的优势
单例模式有许多优势,特别适用于Unity游戏开发:
-
全局访问:单例模式提供了一个全局访问点,允许从任何地方轻松访问对象。这对于跟踪游戏状态、管理资源或共享数据非常有用。
-
节省资源:由于只有一个实例存在,单例模式可以帮助避免不必要的内存浪费。这对于在Unity中管理资源非常重要,特别是在移动平台上。
-
线程安全:单例模式通常是线程安全的,这意味着多个线程可以同时访问单例对象而不会引发竞态条件。
三、两种单例模式的写法
在Unity中,实现单例模式时可以选择使用继承自MonoBehaviour
的单例(MonoSingleton)或不继承的单例(NonMonoSingleton)。它们各自适用于不同的场景和需求。
MonoSingleton(继承自MonoBehaviour的单例)
MonoSingleton是指继承自MonoBehaviour
的单例类。这种类型的单例通常用于需要与Unity场景交互、访问Unity组件或受Unity生命周期影响的情况。它的特点包括:
-
与Unity集成:由于继承自
MonoBehaviour
,MonoSingleton可以访问Unity引擎的功能、生命周期回调和场景对象。这对于管理游戏状态、处理输入、更新UI等与Unity相关的任务非常有用。 -
在场景中可见:MonoSingleton通常在Unity场景中可见,可以直接在Hierarchy中找到。
-
生命周期管理:它可以使用
Awake
、Start
、Update
等生命周期回调方法,从而更好地与游戏对象集成。
示例代码:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Mr.Le.Utility.Singleton
{
/// <summary>
/// 继承MonoBehaviour的单例模式基类
/// </summary>
public class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
{
private static T _instance;
private static object _lock = new object();
//构造方法私有化,防止外部new对象
protected MonoSingleton(){}
public static T Instance
{
get
{
if (_instance == null)
{
lock (_lock)
{
_instance = FindObjectOfType<T>();
if (_instance == null)
{
GameObject go = new GameObject(typeof(T).Name);
_instance = go.AddComponent<T>();
}
}
}
return _instance;
}
}
protected virtual void Awake()
{
if (_instance == null)
{
_instance = (T)this;
DontDestroyOnLoad(gameObject); //切换场景不销毁对象
}
else
{
Destroy(gameObject);
}
}
protected virtual void OnDestroy()
{
_instance = null;
}
private void OnApplicationQuit()
{
_instance = null;
}
}
}
NonMonoSingleton(不继承自MonoBehaviour的单例)
NonMonoSingleton是指不继承自MonoBehaviour
的单例类。这种类型的单例适用于不需要与Unity引擎直接交互的纯逻辑类,例如全局数据管理、资源管理、配置管理等。它的特点包括:
-
独立性:它独立于Unity场景和生命周期,不具有Unity生命周期回调。
-
无需GameObject:NonMonoSingleton不需要附加到游戏对象,因此在Hierarchy中不可见。
-
纯逻辑:它主要用于处理游戏逻辑,而不直接与Unity组件或场景进行交互。
示例代码:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Mr.Le.Utility.Singleton
{
/// <summary>
/// 不继承MonoBehaviour的单例模式基类
/// </summary>
public class NoMonoSingleton<T> where T : NoMonoSingleton<T> //泛型T必须为这个类本身或者是它的子类
{
private static T _instance;
private static object _lock = new object();
//构造方法私有化,防止外部new对象
protected NoMonoSingleton() {}
public static T Instance
{
get
{
if (_instance == null)
{
lock (_lock)
{
//使用反射,调用无参构造方法创建对象(跟new对象一样)
_instance ??= Activator.CreateInstance(typeof(T), true) as T;
}
}
return _instance;
}
}
}
}
四、总结
单例模式在Unity游戏开发中非常有用,它可以确保只有一个实例存在,提供全局访问点,节省资源并确保线程安全。通过遵循上述步骤,你可以轻松地在Unity中实现单例模式,并应用它来管理游戏中的全局状态和资源。这对于创建复杂的游戏系统和维护良好的代码结构非常有帮助。
选择使用哪种类型的单例取决于你的项目需求。如果需要与Unity场景、组件和生命周期交互,通常使用MonoSingleton更为合适。如果需要一个独立于Unity的全局单例,那么NonMonoSingleton可能更适合。无论选择哪种方式,单例模式可以帮助你管理全局状态和资源,确保只有一个实例存在。