2011-11-15 2 views
17

Tôi có 2 lớp chung, một Lớp BaseComponent và lớp BaseManager.thông số chung loại tròn

Cả hai đều trừu tượng và được dự định sẽ được làm cụ thể.

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

BaseManager có một danh sách các BaseComponents, đó là lý do tôi muốn làm cho nó chung chung, do đó, một PhysicsManager : BaseManager<PhysicsComponent> sẽ có một danh sách PhysicsComponents.

Tôi muốn (hoặc đúng hơn, nghĩ rằng tôi cần) BaseComponent là chung chung vì tôi chỉ muốn các lớp học bắt nguồn từ BaseComponent để được 'đính kèm' với người quản lý phù hợp của họ. Lý tưởng nhất là tôi không muốn phải viết một hàm tạo cho mỗi thành phần dẫn xuất chỉ vì vậy tôi có thể thêm nó vào một lớp quản lý cụ thể được truyền vào. Lý tưởng nhất là tôi muốn có một nhà xây dựng có lớp trừu tượng BaseManager.

Tôi làm cách nào để quản lý loại phụ thuộc vòng tròn này?

+0

Tôi rất muốn xem xét thiết kế lại để tránh sự phụ thuộc vòng tròn. Ví dụ, làm cho 'BaseComponent' không chung chung. Có nó phụ thuộc vào một 'IManager'. Đặt dàn diễn viên từ 'BaseComponent' vào' TComponent' trong 'BaseManager ' –

+0

Tôi đồng ý rằng nó hơi có mùi như Jon đã chỉ ra, nhưng tôi không thực sự tuân theo. Nếu 'BaseComponent' phụ thuộc vào' IManager', làm cách nào tôi đảm bảo rằng tất cả các lớp dẫn xuất của 'BaseComponent' có một hàm tạo chấp nhận việc triển khai thực hiện' IManager' chính xác để tôi có thể thêm nó vào danh sách của Manager? Nếu bạn đã có thời gian, tôi sẽ đánh giá cao việc xây dựng một câu trả lời. –

Trả lời

25

Có vẻ như bạn có thể muốn có hai tham số kiểu chung chung:

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> 

Vâng, nó có mùi - nhưng đó là loại điều tôi đã thực hiện trong Protocol Buffers.

Vì vậy, sau đó bạn sẽ phải:

public class PhysicsManager : BaseManager<PhysicsComponent, PhysicsManager> 

public class PhysicsComponent : BaseComponent<PhysicsComponent, PhysicsManager> 
2

Các khớp nối loosest sẽ là nếu thành phần không biết về các nhà quản lý của họ. Đây là một ví dụ về cách thức đó sẽ làm việc. Lưu ý rằng phương pháp này đòi hỏi một số loại cơ chế nhà máy nếu tất cả các thành phần phải được thêm vào một người quản lý. (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); 
} 

Nếu thành phần không thể không phụ thuộc vào các nhà quản lý của họ, tôi nghĩ rằng nó sẽ tốt hơn mà chúng phụ thuộc vào một giao diện được định nghĩa bởi nhu cầu của các thành phần. Đây là 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(); 
    } 
} 

Nhược điểm là hệ thống kiểu không thi hành mà người quản lý chính xác vượt qua, và các diễn viên trong BaseManager sau đó sẽ thất bại. Tôi vẫn thích cách này và "giữ mùi trong cơ sở hạ tầng của tôi" thay vì có các mẫu tròn gây ô nhiễm tất cả các thành phần và quản lý cụ thể của tôi.

+0

Cảm ơn rất nhiều vì câu trả lời rất chi tiết! –

+0

Thú vị. Lưu ý rằng các phụ thuộc vòng tròn có thể được thực hiện bằng cách sử dụng các giao diện thuần túy, vì vậy chúng không gây ô nhiễm các thành phần và trình quản lý cụ thể. Tên loại chung có thể được rút ngắn bằng chỉ thị 'using' (ví dụ: http://stackoverflow.com/a/161484/1429390). –