循环泛型类型参数

本文关键字:泛型类型参数 循环 | 更新日期: 2023-09-27 18:14:35

我有2个通用类,一个BaseComponent类和一个BaseManager类。

它们都是抽象的,都是要具体化的。

public abstract class BaseManager<T> where T : BaseComponent<?>
public abstract class BaseComponent<T> where T : BaseManager<?>

BaseManager有一个BaseComponents列表,这就是为什么我想让它通用,所以PhysicsManager : BaseManager<PhysicsComponent>会有一个PhysicsComponents列表。

我想(或者更确切地说,我认为我需要)BaseComponent是通用的,因为我只希望从BaseComponent派生的类被"附加"到它们适当的管理器。理想情况下,我不想为每个派生组件编写构造函数,这样我就可以将其添加到传入的具体管理器类中。理想情况下,我想有一个构造函数,接受抽象的BaseManager类。

我如何管理这种循环依赖?

循环泛型类型参数

听起来您可能希望有两个泛型类型参数:

public abstract class BaseManager<TComponent, TManager>
    where TComponent : BaseComponent<TComponent, TManager>
    where TManager : BaseManager<TComponent, TManager>
public abstract class BaseComponent<TComponent, TManager>
    where TComponent : BaseComponent<TComponent, TManager>
    where TManager : BaseManager<TComponent, TManager>

是的,它很臭-但这就是我在协议缓冲区中所做的事情。

然后是:

public class PhysicsManager : BaseManager<PhysicsComponent, PhysicsManager>
public class PhysicsComponent : BaseComponent<PhysicsComponent, PhysicsManager>

最松散的耦合是组件不知道它们的管理器。这里有一个例子说明它是如何工作的。请注意,如果必须将所有组件添加到管理器中,则此方法需要某种工厂机制。(Nat Pryce - "如果两个物体之间存在某种关系,那么其他物体应该建立这种关系。")

abstract class BaseComponent
{
    public event EventHandler SomethingHappened;
}
abstract class BaseManager<TComponent> where TComponent : BaseComponent
{
    List<TComponent> components = new List<TComponent>();
    public virtual void AddComponent(TComponent component)
    {
        components.Add(component);
        component.SomethingHappened += (s, e) => OnSomethingHappened(component);
    }
    public abstract void OnSomethingHappened(TComponent component);
}

如果组件不能独立于它们的管理器,我认为它们依赖于由组件需求定义的接口会更好。这是接口隔离原则

interface IManager
{
    void ManageMe(BaseComponent component);
}
abstract class BaseComponent
{
    public BaseComponent(IManager manager)
    {
        manager.ManageMe(this);
    }
}
abstract class BaseManager<TComponent> : IManager where TComponent : BaseComponent
{
    void IManager.ManageMe(BaseComponent component)
    {
        ManageMe((TComponent)component);
    }
    protected abstract void ManageMe(TComponent component);
}
interface IPhysicsManager : IManager
{
    void AnotherCallback(PhysicsComponent comp);
}
abstract class PhysicsComponent : BaseComponent
{
    public PhysicsComponent(IPhysicsManager manager)
        : base(manager)
    {
        manager.AnotherCallback(this);
    }
}
abstract class PhysicsManager : BaseManager<PhysicsComponent>, IPhysicsManager
{
    protected override void ManageMe(PhysicsComponent component)
    {
        throw new NotImplementedException();
    }
    public void AnotherCallback(PhysicsComponent comp)
    {
        throw new NotImplementedException();
    }
}

缺点是类型系统不强制传入正确的管理器,并且BaseManager中的强制转换会失败。我仍然喜欢这种方式,"在我的基础设施中保持气味",而不是让循环模板污染我所有的具体组件和管理器。