【问题标题】:Modeling (and mapping) a class-hierarchy with two degrees of polymorphism?建模(和映射)具有两个多态度的类层次结构?
【发布时间】:2012-02-24 19:13:08
【问题描述】:

我遇到了这样一种情况,即在父/子层次结构中,我有两级多态性,一个在另一个内部。

我认为这最好用一个简单的例子来解释:

    class Group
    {
        public IList<Person> People { get; set; }
    }

    class SpecialGroup : Group
    {
        public IList<SpecialPerson> People { get; set; }
    }

    class Person {}

    class SpecialPerson : Person {}

所以一个Group有一个Person对象的列表,而一个专门的Group(SpecialGroup)有一个专门的Person(SpecialPerson)对象列表。

这可以编译,但我收到警告说我应该在 SpecialGroup.People 上使用“new”关键字,因为它隐藏了 Group.People 属性。

我理解这意味着什么,但也许我不完全理解如何在 C# 中正确地建模这样的东西。关于如何以更好的方式对此建模有任何想法吗?

另外,知道这将如何与 NHibernate 一起玩吗?我不确定使用“new”关键字是否会减少它,因为 Group.People 属性已经被映射为不同的类型。有没有更好的方法来模拟这个,以一种与 NH 兼容的方式?


好的,我想到了一种使用泛型对此进行建模的方法:

    abstract class AbstractGroup<PersonType>
        where PersonType : Person
    {
        public IList<PersonType> People { get; set; }
    }

    class Group : AbstractGroup<Person>
    {}

    class SpecialGroup : AbstractGroup<SpecialPerson>
    {}

    class Person {}

    class SpecialPerson : Person {}

我认为这是我想要的?现在 Person 可以与 SpecialPerson 共享特征,但只能将 SpecialPerson 添加到 SpecialGroup。 AbstractGroup 基类型可以对任何组共有的特征进行建模。

现在的问题是,如果我尝试绘制这个地图,NH 会不会爆炸?


据记录,似乎有些人已成功使用泛型类的查询 - 对于 HQL 查询(我的用例),这是不受支持的。

我想到的另一种方法是简单地隐藏父级的属性实现,例如对子类中的覆盖属性使用“new”关键字 - 以下线程讨论了为什么这也不起作用:

NHibernate: Table Per Subclass Mapping and the New Keyword

到目前为止的结论:运行时检查和异常,正如下面@empi 提出的那样。

【问题讨论】:

  • 为什么SpecialGroup需要继承Group?
  • 嗯,这是一个非常简单的例子——但是 SpecialGroup 与 Group 有很多共同点,所以它确实需要继承。该示例仅显示了我认为对问题本身至关重要的内容。

标签: c# oop nhibernate mapping polymorphism


【解决方案1】:

这种情况也称为“并行”或“双重”继承。

通常在一个层次结构中有一个特定的类,它与另一个层次结构相关。

虽然不是必需的,但最好每个类都有一个“通用”或“抽象”类,必须重写,但是,已经有了依赖的概念。

这种情况在图形界面控件中非常常用,但是, 可能适用于其他场景。

在这种特殊情况下,通常最好只显示第一级

............................................................
....+----------------+................+----------------+....
....|  <<Abstract>>  |..<<contains>>..|  <<Abstract>>  |....
....| AbstractGroup  +<>--------------+ AbstractPerson |....
....|                |................|                |....
....+----------------+................+----------------+....
............................................................

Altought,你可以建模多个关卡,这个不推荐

............................................................
....+----------------+................+----------------+....
....|  <<Abstract>>  |..<<contains>>..|  <<Abstract>>  |....
....| AbstractGroup  +<>--------------+ AbstractPerson |....
....|                |................|                |....
....+-------+--------+................+--------+-------+....
............|..................................|............
............|..................................|............
............^..................................^............
............|..................................|............
............|..................................|............
....+-------+--------+................+--------+-------+....
....|  <<Concrete>>  |..<<contains>>..|  <<Concrete>>  |....
....|      Group     +<>--------------+     Person     |....
....|                |................|                |....
....+----------------+................+----------------+....
............|..................................|............
............|..................................|............
............^..................................^............
............|..................................|............
............|..................................|............
....+-------+--------+................+--------+-------+....
....|  <<Concrete>>  |..<<contains>>..|  <<Concrete>>  |....
....|   SchoolGroup  +<>--------------+     Student    |....
....|                |................|                |....
....+----------------+................+----------------+....
............................................................

您提到 NHibernate,您的类是否代表要存储的数据?

一些类似的问题:

Avoiding parallel inheritance hierarchies

Parallel Inheritance Hierarchy Refactoring

How to avoid parallel inheritance hierarchies among GUI controls and domain objects

Parallel Inheritance between Interface Classes and Implementation Classes in C++

干杯。

【讨论】:

  • 感谢您的努力!但是,是的,这是持久模型的一部分——子对象不仅仅是包装在对象中的函数,它们是具有附加属性和功能的不同实体。此外,我发现 HQL 中不支持通用查询。所以恐怕@empi 的建议是唯一对我有用的建议......
  • @mindplay.dk :我使用过数据库实体和并行层次结构,但从来没有一起工作过。我还有生成实体的工具,这些工具具有其他缺失的功能。我最终可能会制作自己的实体生成器,它支持缺少的功能;-)
  • 您使用什么工具生成实体?我正在使用一个根本无法正常工作的...
  • @mindplay.dk :我使用了我的一个工作中提供的自定义工具。其他工作也有自己的工具。我也使用过 codesmith,但是,它的付费软件。我实际上正在寻找一个开源的,并且已经开始了我自己的,但是,还没有完成。
【解决方案2】:

如果您想强制执行 SpecialGroup 仅包含 SpecialPerson 的规则,那么您可以通过编程方式执行此操作,而无需隐藏 People 属性。我猜你有一些方法AddPerson。如果有人试图添加不是SpecialPerson 的条目,您可以在SpecialGroup 中覆盖它并抛出异常。如果您想获得SpecialPerson 的列表,那么您可以添加方法IEnumerable&lt;SpecialPerson&gt; GetSpecialPeople() 并将Person 转换为SpecialPerson(它始终是有效的转换,因为您正在检查AddPerson 方法中的类型)。通过这样做,您不必隐藏 People 属性,NHibernate 就可以正常工作。

【讨论】:

  • 是的,这行得通——每一个问题都可以用更多的代码来解决。我希望找到一种利用强类型和编译时安全性而不是运行时检查的解决方案......
  • 如果没有 NHibernate,你将如何解决它?你说 Group 包含 Person 的集合,然后你想说 SpecialGroup 没有。您要么必须在代码中检查它(或破解它;)),要么创建一些没有 People 的抽象组。当然,您可以尝试一些使用泛型的解决方案,但我从未尝试过使用 NHibernate。
  • 正如我所说的您当然可以尝试一些使用泛型的解决方案,但我从未尝试过使用 NHibernate 的解决方案ayende.com/blog/2951/nhibernate-and-generic-entities 底线是有可能,但不要这样做
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-06
相关资源
最近更新 更多