使用 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>
,它提供了获取 Manager
、Singleton<Manager>.GetInstance()
实例的方法。您的 GameManager
现在继承自 Manager
并继承自 Singleton<Manager>
。
正如您在 GameManager.Initialize()
中所做的那样,您可以使用 SetSingleton
设置管理器单例,它接受 GameManager
作为参数,因为它需要一个 Manager
,你的 GameManager
是。
但是你的GameManager
仍然只实现了Singleton<Manager>
,这意味着GetInstance()
方法只能return一个Manager
,而不是GameManager
,尽管您找回的经理实际上是您的GameManager
。您现在可以将其转换为 GameManager
并且它会起作用,尽管那将是一个相当不干净的解决方案。
也就是说:我认为尝试通过接口强制执行单例模式不是一个干净的解决方案,正如评论中已经指出的那样。如果您想使用单例管理器实例,我建议您研究一下依赖注入。对于 Unity,我强烈推荐 Zenject。如果您之前从未使用过 DI,那么需要一些时间来习惯,但正确使用它会使您的代码更清晰;我不想在我的项目中错过它。
我正在创建一个 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>
,它提供了获取 Manager
、Singleton<Manager>.GetInstance()
实例的方法。您的 GameManager
现在继承自 Manager
并继承自 Singleton<Manager>
。
正如您在 GameManager.Initialize()
中所做的那样,您可以使用 SetSingleton
设置管理器单例,它接受 GameManager
作为参数,因为它需要一个 Manager
,你的 GameManager
是。
但是你的GameManager
仍然只实现了Singleton<Manager>
,这意味着GetInstance()
方法只能return一个Manager
,而不是GameManager
,尽管您找回的经理实际上是您的GameManager
。您现在可以将其转换为 GameManager
并且它会起作用,尽管那将是一个相当不干净的解决方案。
也就是说:我认为尝试通过接口强制执行单例模式不是一个干净的解决方案,正如评论中已经指出的那样。如果您想使用单例管理器实例,我建议您研究一下依赖注入。对于 Unity,我强烈推荐 Zenject。如果您之前从未使用过 DI,那么需要一些时间来习惯,但正确使用它会使您的代码更清晰;我不想在我的项目中错过它。