DDD集合:在模型中包含版本控制

时间:2018-07-18 22:18:34

标签: domain-driven-design entities event-sourcing value-objects

在DDD尝试中,我定义了以下无处不在的语言:

一个产品可以有多个图纸。工程图由工程图编号,修订号*和多个附件**组成。可以使用具有不同修订号的新图形来修改图形。

不变式:

  • 产品具有的每个图纸编号只能有一个当前版本。
  • 不能有图纸号和版本相同的图纸

*有时最初是空的
**附件是实际的产品图纸,可以是.jpg,.pdf,.stp等。
语言是否不匹配?这些附件也可以称为实际图纸,其中上述属性只是通过编程方式区分它们的元数据。

在某些情况下,应用程序应有助于企业开发产品。图纸是概念,在讨论和修订之后,这些图纸将成为样本,必须得到客户的认可。在这种情况下,由于业务价值,我选择了事件源架构来评估产品的增量开发。


我遇到的问题是是否将这些过去的修订版本放入模型中。这可以通过向图形添加一个布尔属性来完成,该属性指示它们是否为当前使用的图形。但是,这违背了我的直觉,认为将图形建模为不可变的值对象(现在图形具有可变属性)。在我的脑海中,我支持这种直觉,认为一旦更改了图形,就会生成具有不同修订号的新图形。

我还有另一种感觉,那就是我应该将过去的修订版放入模型中,因为它们具有商业价值。让产品具有当前图纸和以前图纸的列表是一个好的解决方案吗?

我应该如何考虑用户何时要更正图纸?例如,当某人没有将所有正确的文件附加到图形上,而您以后又想通过添加更多文件或删除某些文件来进行更正?


代码示例

举一个简短的示例代码,这是我想出的一件事,即将图形作为值对象,在equals方法中使用图形编号和修订版本:

    public class Product {

        private Set<Drawing> currentDrawings;
        private Set<Drawing> oldDrawings;

    }

    public class Drawing {

        private String drawingNumber;
        private String revision;
        private Set<URL> files;

        @Override 
        public boolean equals(Object o) {
            if (o == this) return true;
            if (!(o instanceof Drawing)) return false;
            Drawing other = (Drawing ) o;
            if (this.drawingNumber != other.drawingNumber) return false;
            if (this.revision != other.revision) return false;
            return true;
        }

        //getters and constructor omitted for brevity
    }

没有足够的声誉来回答Luiz E's comment,因此我将其放在此处:在某些情况下,产品由不同的零件,材料等组成。有时候,有一个清晰的父工程图引用了其他子工程图,而其他时候,只有一堆零件图将在以后组装。

我倾向于坚持“ KISS”原则,而不是对图纸之间的所有这些不同关系进行建模,这些关系只会使用户(他们不是图纸的创建者)感到困惑。

1 个答案:

答案 0 :(得分:0)

  

供以后参考,当根据DDD设计汇总时   原则,应保持骨料清洁而不污染   使用聚合(部分)的早期版本进行建模。记住   您希望模型代表当前状态   聚集。

     

如果集合(部分)的较早状态具有某种   商业价值,则应考虑事件来源或其他模式   允许审核日志或版本控制。

对于这个特定问题,“产品”聚合和“绘图”值对象可能看起来像这样:

public class Product {

    private Map<String, Drawing> drawings;

}

public class Drawing {

    private String drawingNumber;
    private String revision;
    private Set<URL> files;

    @Override 
    public boolean equals(Object o) {
        if (o == this) return true;
        if (!(o instanceof Drawing)) return false;
        Drawing other = (Drawing ) o;
        if (this.drawingNumber != other.drawingNumber) return false;
        if (this.revision != other.revision) return false;
        return true;
    }

    //getters and constructor omitted for brevity
}

在这里我宁愿使用Map而不是Set的原因是,您希望每个图形编号仅具有一个修订,并且每个图形都必须具有唯一的图形编号。如果您在地图中使用图形编号作为键值并将简单的修改后的图形放在图形编号Key上,那么这很容易实现,因为它将替换旧的Value对象。

由于应通过比较图纸编号和修订版来将其视为相等,因此(如果不是不可能)检查是否没有重复的图纸编号会比较困难。您可以通过仅将工程图与其工程图编号进行比较来解决此问题,但这会破坏修订的定义(对工程图的更正,使之成为不同的工程图)。