トリッキーなモデリングの問題があります。別の観点から見ていきたいと思います。
一部のエンジンで全体として扱われるモデルを扱っています。次のようになります(名前は私たちが使用しているものではありません):
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つの特定のモデルを作成する必要があるということです。
現在、コンテナ-グループ-要素の3つのクラスを持つモデルがあります。
同じ構造を共有する特定のモデルを作成する必要がありますが、モデル全体に特定のクラスがあります。
- BaseContainer、BaseGroup、BaseElement(親)
- ContainerFoo-GroupFoo-ElementFoo(最初の子)
- ContainerBar-GroupBar-ElementBar(2番目の子)
そして、完全を期すために、最も重要なことは、強く型付けされたコレクションが必要なことです。たとえば、親タイプのリストではなく、ContainerFooのGroupFooのリストが必要です。
これを実現する2つの方法を検討しました。ジェネリックスと新しいプロパティの作成です。
例えば:
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では実際には使用できません。
2番目の解決策:
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.
この2番目の解決策について、私が気に入らない点をはっきりと理解できると思います。
これ以上のアイデアはありますか?