使用 C# 接口创建实现单例模式的管理器 class,但 child 管理器 class 没有单例模式

using C# interface to create a Manager class that implementing a singleton pattern, but the child manager class does not have a singleton pattern

我正在创建一个 Manager class,它使用 C# 接口实现单例模式。

我想出了一个结构,将单例模式应用于 Manager class,将其继承到我的 children,并扩展功能。 但是,如果我尝试从另一个 class 访问它,我只能访问 Manager class.

我觉得我需要修改代码或结构,我该怎么办?

ISingleton.cs

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

public interface ISingleton<T> where T : class
{
    void SetSingleton(T _classType, GameObject _obj);
    T GetInstance();
}

Singleton.cs

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

public abstract class Singleton<T> : MonoBehaviour , ISingleton<T> where T: class
{
    public static T instance = default;
    public void SetSingleton(T _class, GameObject _obj)
    {
        if (instance is null) instance = _class;
        else if(instance.Equals(_class))
        {
            Debug.LogError("Unexpected Instancing Singleton Occuired! from " + gameObject.name);
            Destroy(_obj);
            return;
        }
        DontDestroyOnLoad(_obj);
    }
    public T GetInstance()
    {
        return instance;
    }
}

Manager.cs

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

public class Manager : Singleton<Manager>,IManager
{
    public int data;

    protected virtual void Awake()
    {
        Initialize();
    }

    public virtual void Initialize()
    {
        SetSingleton(this,this.gameObject);
    }
}

游戏管理器

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

public class GameManager : Manager
{
    public int HP,point;
    protected override void Awake()
    {
        Initialize();
    }
    public override void Initialize()
    {
        SetSingleton(this, this.gameObject);
    }

    private void StartGame() => print("GameStart");
    private void PauseGame() => print("Game Paused");
    private void QuitGame() => Application.Quit();
}

下面是我的代码的大致结构。

您的 Manager class 派生自 Singleton<Manager>,它提供了获取 ManagerSingleton<Manager>.GetInstance() 实例的方法。您的 GameManager 现在继承自 Manager 并继承自 Singleton<Manager>

正如您在 GameManager.Initialize() 中所做的那样,您可以使用 SetSingleton 设置管理器单例,它接受 GameManager 作为参数,因为它需要一个 Manager ,你的 GameManager 是。

但是你的GameManager仍然只实现了Singleton<Manager>,这意味着GetInstance()方法只能return一个Manager,而不是GameManager ,尽管您找回的经理实际上是您的GameManager。您现在可以将其转换为 GameManager 并且它会起作用,尽管那将是一个相当不干净的解决方案。

也就是说:我认为尝试通过接口强制执行单例模式不是一个干净的解决方案,正如评论中已经指出的那样。如果您想使用单例管理器实例,我建议您研究一下依赖注入。对于 Unity,我强烈推荐 Zenject。如果您之前从未使用过 DI,那么需要一些时间来习惯,但正确使用它会使您的代码更清晰;我不想在我的项目中错过它。