JunYoung Yoon
JunYoung Yoon

Reputation: 43

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

I am creating a Manager class that implements singleton patterns with C# interface.

I came up with a structure to apply a singleton pattern to the Manager class, inherit it to my children, and extend the functionality. However, if I try to access it from the other class, I can only access the Manager class.

I think I need to modify the code or structure, what should I do?

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);
    }
}

GameManager

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();
}

Below is the rough structure of my code.

Singleton interface oriented Manager

Upvotes: 0

Views: 755

Answers (1)

Theobald Beyer
Theobald Beyer

Reputation: 174

Your Manager class derives from Singleton<Manager>, which provides a method to get an instance of Manager, Singleton<Manager>.GetInstance(). Your GameManager now inherits from Manager and with that from Singleton<Manager>.

As you already do in GameManager.Initialize(), you can set the manager singleton with SetSingleton, and it accepts the GameManager as argument, because it expects a Manager, which your GameManager ist.

But your GameManager still only implements Singleton<Manager>, meaning the GetInstance() method can only return a Manager, not a GameManager, although the manager you get back is actually your GameManager. You could cast that now to a GameManager and it would work, although that would be a rather unclean solution.

That said: I think trying to enforce a singleton pattern via interface is not a clean solution, as was pointed out in comments already. If you want to work with singleton manager instances, I would advise you to look into dependency injection. For Unity I can highly recommend Zenject. If you never worked with DI before it takes a moment to get used to, but used correctly it makes your code cleaner; I for one would not want to miss it in my projects.

Upvotes: 2

Related Questions