统一使用Singleton的最佳方法 [英] Best way to use Singletons in unity

查看:65
本文介绍了统一使用Singleton的最佳方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道哪种方法是使用单例实例的正确方法:当我创建一个名为"Manager"的单例类,并且它包含一个名为"value"的int变量,而我又有一个名为"A"的类.../p>

    //singleton class
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    public class Manager : MonoBehaviour {
        public static Manager Instance{ set; get;}
        public int value;
        private void Awake () {
            if (Instance == null) {
                Instance = this;
                DontDestroyOnLoad (this.gameObject);
            } else {
                Destroy (gameObject);
            }
        }
    }

因此,在我的A类中,我可以像下面这样创建单例的实例: //示例伪代码 公共A级 {

        // First
        // using as a global variable
        Manager manager;

        //------------------------------------

        Public void tstOne(){
             // First
             // using that global variable
             manager.Instance.value = 0;

             // Second
             // or this way
             Manager.Instance.value = 0; 
        }
        Public void tstTwo(){
             // First
             // using that global variabl
             manager.Instance.value = 1;

             // Second
             // or this way
             Manager.Instance.value = 1; 
        }
    }

所以我的问题是-我应该创建一个全局实例,然后像第一个实例一样使用该实例,还是应该使用第二个实例?

它们在内存消耗和效率方面是否都相同? 还是有使用单身人士的另一种方法?

解决方案

我确认Ruzihm的回答(我也同意derHugo的评论,我个人更喜欢SO,并在需要时引用它们.比Singleton或DI直接方法干净得多).

要特定地访问实例成员manager.Instance.value的速度较慢,并且还需要在堆上分配更多的内存,因此会损害内存使用率和速度性能. (非常小的性能问题,但仍然如此.)

单身人士还有进一步的改进空间,尤其是如果您不要求它源自MonoBehaviour.

您可以:

  1. 如果您忘记将其添加到场景中,请确保它也是构建的
  2. 使其具有线程安全性(通常不需要统一)
  3. 懒惰地实现它(意味着您仅在需要时创建它)
  4. 此外,通常最好密封单例类以提高性能(再次使用虚拟方法时确实略有改进)

这将是实现(考虑将Manager用作帮助程序实例,如果需要单行为逻辑,则将YourManagerMono用作:

 public class YourManagerMono : MonoBehaviour
{
}

public sealed class Manager
{
    private static readonly Manager instance = new Manager();
    //use a gameobject to relate it in the scene
    private YourManagerMono monoManager;

    public static Manager Instance => instance;

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static Manager() {}

    private Manager()
    {
        //find or create a manager
        monoManager = GameObject.FindWithTag("Manager").GetComponent<YourManagerMono>();
        if (monoManager == null)
        {
            monoManager = new GameObject().AddComponent<YourManagerMono>();
            monoManager.gameObject.tag = "Manager";
            Object.DontDestroyOnLoad(monoManager.gameObject);
        }
    }
}
 

Jon Skeet撰写的有关C#的单例实现的很棒的文章(我使用实现4)./p>


我再次同意derHugo(在有关此答案的新评论中).我的示例用于显示有趣的预期结果并提供尽可能多的性能,但是如果您只需要具有第1点和第3点的Monohhaviour,则可以继续使用

    //singleton class
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    public class Manager : MonoBehaviour {
        public static Manager Instance{ set; get;}
        public int value;
        private void Awake () {
            if (Instance == null) {
                Instance = this;
                DontDestroyOnLoad (this.gameObject);
            } else {
                Destroy (gameObject);
            }
        }
    }

So inside my A class I can make a instance of the singleton like this: // example pseudo code public class A {

        // First
        // using as a global variable
        Manager manager;

        //------------------------------------

        Public void tstOne(){
             // First
             // using that global variable
             manager.Instance.value = 0;

             // Second
             // or this way
             Manager.Instance.value = 0; 
        }
        Public void tstTwo(){
             // First
             // using that global variabl
             manager.Instance.value = 1;

             // Second
             // or this way
             Manager.Instance.value = 1; 
        }
    }

So my problem is - should I create A global instance and then use that instance like in first one or should I use the second example?

Are they both are same in terms of memory consumption and efficiency? Or is there another way to use singletons?

解决方案

I confirm Ruzihm answer (and I also agree with derHugo comment, I personally prefer SO and reference them where required. Much cleaner than Singleton or DI direct approach).

To be specific accessing the instance member manager.Instance.value is slower and also requires further memory allocation on the heap so it hurts both memory usage and speed performance. (Very small performance issues, but still.)

There's also further room of improvement on the singleton, especially if you do not require it to derive from MonoBehaviour.

You can:

  1. Make sure it is build also if you forget to add it in the scene
  2. Make it thread safe (not required by unity, usually)
  3. Implement it lazily (means you create it only when you need it)
  4. Also, as a general rule is better to seal the singleton class for improved performance (again really slight improvement when you use virtual methods)

This would be the implementation (considering you use the Manager as helper instance and YourManagerMono if you require monobehaviour logic:

public class YourManagerMono : MonoBehaviour
{
}

public sealed class Manager
{
    private static readonly Manager instance = new Manager();
    //use a gameobject to relate it in the scene
    private YourManagerMono monoManager;

    public static Manager Instance => instance;

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static Manager() {}

    private Manager()
    {
        //find or create a manager
        monoManager = GameObject.FindWithTag("Manager").GetComponent<YourManagerMono>();
        if (monoManager == null)
        {
            monoManager = new GameObject().AddComponent<YourManagerMono>();
            monoManager.gameObject.tag = "Manager";
            Object.DontDestroyOnLoad(monoManager.gameObject);
        }
    }
}

A great article about singleton implementation for C# by Jon Skeet (I used implementation 4).

EDIT:
Again I agree with derHugo (in the new comment on this answer). My example is used to show an interesting prospective and to offer as much performance as I can, but if you just require a Monobehaviour with just point 1 and 3 you may go ahead with a generic implementation of singleton from Unify Community (just remember to set the end class as sealed to help the compiler).

这篇关于统一使用Singleton的最佳方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆