Unity常用设计模式-单例模式:游戏中的独一无二

一、简介

当谈到Unity游戏开发时,设计模式是一个非常重要的主题,其中之一就是单例模式。单例模式是一种创建模式,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例。在Unity中,单例模式经常用于管理全局游戏状态、资源管理、对象池等方面。在本文中,我们将探讨Unity中如何实现单例模式以及其优势。

二、单例模式的优势

单例模式有许多优势,特别适用于Unity游戏开发:

  1. 全局访问:单例模式提供了一个全局访问点,允许从任何地方轻松访问对象。这对于跟踪游戏状态、管理资源或共享数据非常有用。

  2. 节省资源:由于只有一个实例存在,单例模式可以帮助避免不必要的内存浪费。这对于在Unity中管理资源非常重要,特别是在移动平台上。

  3. 线程安全:单例模式通常是线程安全的,这意味着多个线程可以同时访问单例对象而不会引发竞态条件。

三、两种单例模式的写法

在Unity中,实现单例模式时可以选择使用继承自MonoBehaviour的单例(MonoSingleton)或不继承的单例(NonMonoSingleton)。它们各自适用于不同的场景和需求。 

MonoSingleton(继承自MonoBehaviour的单例)

MonoSingleton是指继承自MonoBehaviour的单例类。这种类型的单例通常用于需要与Unity场景交互、访问Unity组件或受Unity生命周期影响的情况。它的特点包括:

  • 与Unity集成:由于继承自MonoBehaviour,MonoSingleton可以访问Unity引擎的功能、生命周期回调和场景对象。这对于管理游戏状态、处理输入、更新UI等与Unity相关的任务非常有用。

  • 在场景中可见:MonoSingleton通常在Unity场景中可见,可以直接在Hierarchy中找到。

  • 生命周期管理:它可以使用AwakeStartUpdate等生命周期回调方法,从而更好地与游戏对象集成。

示例代码:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Mr.Le.Utility.Singleton
{
    /// 
    /// 继承MonoBehaviour的单例模式基类
    /// 
    public class MonoSingleton : MonoBehaviour where T : MonoSingleton
    {
        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();
                        if (_instance == null)
                        {
                            GameObject go = new GameObject(typeof(T).Name);
                            _instance = go.AddComponent();
                        }
                    }
                }
    
                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
{
    /// 
    /// 不继承MonoBehaviour的单例模式基类
    /// 
    public class NoMonoSingleton where T : NoMonoSingleton //泛型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可能更适合。无论选择哪种方式,单例模式可以帮助你管理全局状态和资源,确保只有一个实例存在。

你可能感兴趣的:(设计模式,单例模式)