我有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
类的构造函数。
我如何管理这种循环依赖?
答案 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中的强制转换失败。我仍然更喜欢这种方式并“在我的基础设施中保持气味”,而不是让圆形模板污染我所有的具体组件和经理。