2012-06-03 121 views
1

我有一個棘手的建模問題,我想在這個問題上有另一個觀點。使用強類型的模型繼承

我正在處理一個模型,它被一些引擎視爲一個整體。它看起來像(名字是我們使用的不是):

public class Container{ 
    // Some other specific properties and methods, ctor etc 

    public IList<Group> Groups {get; private set;} 

    // For convenience, we need that 
    public IList<Element> Elements {get; private set;} 
} 

public class Group{ 
    // Specific stuff here  

    public IList<Element> Elements{get; private set;} 

    public Container Container{get; set;} 
} 

public class Element{ 
    public Group Group {get; set;} 
} 

一直以來的模式,我們有那些雙引用,因爲模型是作爲一個整體的引擎處理。

現在,棘手的部分:我需要創建2個特定的模型,共享這個組織。

目前,我有三個類的模型:容器 - 組 - 元素。

我需要創建共享相同結構的特定模型,但是在模型中使用特定的類。

  • BaseContainer,BaseGroup,BaseElement(父)
  • ContainerFoo - GroupFoo - ElementFoo(第一胎)
  • ContainerBar - GroupBar - ElementBar(第二個孩子)

而且,爲了完成,最重要的是我需要強類型的集合。例如,我需要ContainerFoo中的GroupFoo列表,而不是父類型的列表。

我探索了兩種實現方法:泛型和創建新屬性。

例如:

public class BaseContainer<TGroup, TElement>{ 
    public IList<TGroup> Groups {get; private set;} 

    public IList<TElement> Elements{get; private set;} 
} 

public class BaseGroup<TContainer, TElement>{ 
    public TContainer Container {get; set;} 

    public IList<TElement> Elements {get; private set;} 
} 

public class BaseElement<TGroup>{ 

    public TGroup Group{get; set;} 

} 

public class ContainerFoo: BaseContainer<GroupFoo, ElementFoo>{ 
    // Specific stuff here 
} 

public class GroupFoo: BaseGroup<ContainerFoo, ElementFoo>{ 
} 

public class ElementFoo: BaseElement<ContainerFoo>{ 
} 

此方法適用於這種情況,而是:

  • 的容器類型列表可能會很長,因爲容器實際上是整個模型的入口點(在這裏簡化)
  • 我們實際上不能將它與protobuf-net一起使用,用於序列化和反序列化。

解決方法二:

public abstract class BaseContainer{ 

    public abstract IList<BaseGroup> Groups {get;} 

    public abstract IList<BaseElement> Elements{get;} 
} 

public abstract class BaseGroup{ 
    public abstract BaseContainer Container {get; set;} 
} 

public abstract class BaseElement{ 

    public abstract BaseGroup Group{get; set;} 
} 

public ContainerFoo : BaseContainer{ 

    public override IList<BaseGroup> Groups { 
    get{ 
     // We are using .Net 4, and we can do that. 
     return (IList<BaseGroup>)this.GroupsFoo; 
    } 
    } 

public IList<GroupFoo> GroupsFoo{ get; private set;} 

// Same thing for elements 
} 

// You see the point, I don't want to create other classes here. 

我想你可以很明顯的看出什麼,我不喜歡這個第二個解決方案!

還有什麼想法?

回答

1

而不是使用abstract/override您可以使用new修改的派生類的屬性:

class Container { 
    public IList<Group> Groups { get; private set; } 
} 

class ContainerFoo : Container { 
    public new IList<GroupFoo> Groups { get { return (IList<GroupFoo>)base.Groups; } } 
} 

另外,有在這裏使用的傳承任何實際的好處?你會更好的定義一個通用的IContainer<T>接口,並取消基類?

interface IContainer<TGroup> where T : Group { 
    IList<TGroup> Groups { get; } 
} 

class ContainerFoo : IContainer<GroupFoo> { 
    public IList<GroupFoo> Groups { get; private set; } 
} 

class ContainerBar : IContainer<GroupBar> { 
    public IList<GroupBar> Groups { get; private set; } 
} 
+0

謝謝。新的修改器可能很有用。我會檢查出來的。不需要在每次訪問時創建一個新的列表實例,似乎我可以轉換它。 – ghusse

+0

關於接口,我有一些需要在基類中實現的常見行爲。 – ghusse

+0

根據您常見行爲的複雜性,可能會將其分爲另一類。我嘗試在可能的情況下使用接口和組合而不是繼承。如果你發現你在不同的時間需要不同的行爲(比如Foo和Bar使用行爲A而Baz使用行爲B),那麼你可以使用策略而不是日益複雜的繼承層次結構。 –