3

我在属于不同聚合的几个实体中有一些共同行为,我想将其纳入抽象类。

让不同聚合中的实体继承自一个公共抽象类有什么缺点吗?


用例

一些实体具有名称、描述或其他可以翻译成不同语言的属性。

例如,我将使用 设置名称setName(language, name)并使用 检索它getName(language)

每种语言的每个文本都存储在一个对象中,例如:

class EntityName
{
    protected Entity entity;
    protected Language language;
    protected String text;
    protected int version;

    public EntityName(Entity entity, Language language)
    {
        this.entity = entity;
        this.language = language;
        this.version = 1;
    }

    // setText(), getText(), ...
}

对于给定的Entity类,EntityNameEntity聚合内。只能通过和Entity来创建、读取和写入。EntityNamesetName()getName()

但是,诸如EntityName, EntityDescription,之类的类OtherEntityName都将共享几乎相同的代码。唯一比变化的部分是对聚合的引用,因此是对构造函数的引用。

4

3 回答 3

4

这个话题不多。但是,请查看这篇题为“如何:领域驱动设计”的文章

特别是,阅读标题为步骤 2 - 识别聚合和聚合根的部分:

在高级情况下,类模型中存在的多态性也会影响聚合边界。当多个聚合根类都共享同一个基类时会发生这种情况

如果您正在存储域模型之外的簿记数据(id、版本、创建时间戳、更新时间戳)(例如,为了支持您的持久层),我不认为这是一个问题。但是,如果您尝试重用真正的业务方法和属性,则可以考虑用组合或 AOP 介绍替换继承。

更新

查看更新后的用例后,您似乎真的在尝试实现代码重用,而不是真正的Liskov is-a关系。一些语言通过mixins (Groovy) 或特征(Scala)等概念更好地支持这种类型的重用。假设 Java,您可以做的一种方法是创建一个类并使用 Project Lombok 的@Delegate注释转发到您的实现。这有以下好处:

  • 提供相同级别的聚合封装
  • 为您生成字节码,没有源代码中的所有重复
  • 允许您将一个继承选项保存为未来真正的 is-a 关系
  • 确保整个域的一致性

我相信这更纯粹,并且可以使您的模型具有灵活性。我在几个项目中使用了 Project Lombok,并取得了巨大的成功。它允许您绕过 Java 中缺少的一些语言功能,并更多地关注您的领域,而不是实现某些惯用语所需的必要样板代码。

于 2012-11-21T14:17:32.370 回答
1

我认为只要通用定义不影响聚合根设计就可以了。也就是说,您开始对聚合根进行建模并注意到它们有很多共同点,因此您提取了一个公共基类。

不过,我会三思而后行,因为从不同的有界上下文聚合根有这么多共同点的几率是多少?这有点像 IMO 的代码气味。

于 2012-11-21T14:26:40.560 回答
0

正确的继承由is-a关系定义。恕我直言,很少有适用于聚合根的情况。

仅仅因为根看起来相似并不意味着它们来自同一个地方。

如果您可以创建一个名称在域中有意义的基类,请继续。如果没有,不要。

于 2012-11-21T16:50:33.650 回答