Reputation: 43
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.
Upvotes: 0
Views: 755
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