圆形泛型类型参数

时间:2011-11-15 15:33:35

标签: c# generics circular-dependency

我有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类的构造函数。

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

2 个答案:

答案 0 :(得分:27)

听起来您可能想要两个通用类型参数:

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>

是的,它很臭 - 但这就是我在Protocol Buffers中所做的事情。

那么你就有了:

public class PhysicsManager : BaseManager<PhysicsComponent, PhysicsManager>

public class PhysicsComponent : BaseComponent<PhysicsComponent, PhysicsManager>

答案 1 :(得分:3)

如果组件不了解他们的经理,最松散的耦合。这是一个如何工作的例子。请注意,如果必须将所有组件添加到管理器,则此方法需要某种工厂机制。 (Nat Pryce - "If a relationship exists between two objects, some other object should establish the relationship."

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 Segregation Principle

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中的强制转换失败。我仍然更喜欢这种方式并“在我的基础设施中保持气味”,而不是让圆形模板污染我所有的具体组件和经理。