2011-11-15 44 views
17

我有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

我會強烈考慮重新設計以避免循環依賴。例如,使'BaseComponent'非通用。它取決於一個'IManager'。將演員從'BaseComponent'放到'BaseManager ' –

+0

'TComponent'我同意這有點臭,Jon指出,但我不太關注。如果'BaseComponent'依賴於一個'IManager',我將如何確保'BaseComponent'的所有派生類都有一個構造函數接受正確的具體'IManager'實現,因此我可以將其添加到管理器列表中?如果你有時間,我會很感激一個答案。 –

回答

25

這聽起來像你可能想有兩個泛型類型參數:

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> 
2

最鬆的耦合是,如果組件不知道他們的經理。這是一個如何工作的例子。請注意,如果必須將所有組件添加到經理中,則此方法需要某種工廠機制。 (NAT普賴斯 - "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投將失敗。我仍然會更喜歡這種方式,並且「保持我的基礎設施中的嗅覺」,而不是使用循環模板污染我所有的具體部件和管理人員。

+0

非常感謝您的詳細解答! –

+0

有趣。請注意,循環依賴可以使用純粹的接口完成,因此它們不會污染具體組件和管理器。泛型類型名稱可以用'using'指令縮短(例如http://stackoverflow.com/a/161484/1429390)。 –