DDD实体构造函数参数

时间:2017-07-24 01:02:59

标签: object entity domain-driven-design aggregate

如果您有一个具有值对象的实体作为属性。

哪个是实体构造函数的参数,值对象?还是值对象的原始类型?

首先,我在实体外构建了值对象,然后将值对象传递给实体构造函数......但后来我意识到可能是实体本身必须构建值对象。

我认为这是因为实体和值对象实际上是一个聚合,并且假设您必须通过聚合根(即通过实体)访问聚合内部。

那么哪种方式正确?是否允许处理实体外的价值对象?或者值对象只能由实体使用?

谢谢。

修改

例如,我有一个实体“任务”,它是聚合根。该实体具有值对象“DeliveryDate”(格式为“dd / mm / yyyy hh:mm”)。实体也有更多的价值对象。

class DeliveryDate extends ValueObject {

    private String formattedDeliveryDate;

    private DeliveryDate() {
        super();
    }

    DeliveryDate ( String formattedDeliveryDate ) {
        this();
        this.setFormattedDeliveryDate ( formattedDeliveryDate );
    }

    private void setFormattedDeliveryDate ( String formattedDeliveryDate ) {
        << check that the string parameter "formattedDeliveryDate" is a valid date in format "dd/mm/yyyy hh:mm" >>
        this.formattedDeliveryDate = formattedDeliveryDate;
    }

    ........     

实体构造函数:

Task ( TaskId taskId, Title title, Delivery deliveryDate, EmployeesList employeesList ) {
    this();
    this.setTaskId(taskId);
    this.setTitle(title);
    this.setDeliveryDate(deliveryDate);
    this.setEmployeesList(employeesList);
}

我的疑问是:这样可以吗? (将DeliveryDate对象传递给构造函数) 或者我应该传递字符串? (并且构造函数创建DeliveryDate对象)

我认为这更像是一个问题“聚合体外部是否应该了解DeliveryDate概念?”

一般来说,我怀疑任何实体的任何价值对象,而不仅仅是Task和DeliveryDate(这只是一个例子)。

我已经提出了有关构造函数的问题,但它也适用于工厂(如果创建实例的过程很复杂)...聚合工厂参数应该是值对象吗?或者用于创建值对象的基元?

2 个答案:

答案 0 :(得分:1)

Domain Driven Design在此处未提供任何具体指导。

一个常见的情况可能是这样的:我们从数据库中检索了一个DTO,现在想要从中创建一个实体......

class Entity {
    private Value v;

    Entity (Value v) {
        if (null == v) throw new IllegalArgumentException();

        this.v = f;
    }

    Entity (DTO dto) {
        this(new Value(dto));
    }

    // ...
}

如果你调用第二个构造函数而不是第一个构造函数,那真的很重要吗?不多。

语言检查:

  

未从数据库中检索DTO。您从数据库中检索的是聚合,而不是DTO

我不得不放弃这个想法 - 这个定义会导致太多问题。

例如,在事件源设计中,数据库通常存储事件的表示,而不是聚合。

即使在传统设计中,它也不会成功 - 聚合的边界由域模型强制执行的约束定义。获取数据out of the domain model后,您剩下的只是状态的表示。换句话说,我们在数据库中保存状态,但不保存行为,而不是约束 - 您无法从保存的数据中导出约束,因为您无法看到边界。

决定哪些数据需要保持内部一致的是模型,而不是数据库。

我倾向于使用术语DTO,因为它的作用是:to carry data between processes - 在这个特定的实例中,在数据库和域模型之间。如果您想使用message或文档,我不会狡辩。

答案 1 :(得分:1)

在您的情况下,两种解决方案似乎相似。如果在实体外部或内部创建值对象,则无关紧要。但是考虑一下你的实体何时会有多个值对象,实体构造函数将包含太多逻辑,以确保它正确地创建VO,同时强制实体的不变量。

避免这种不必要的复杂性的一个解决方案是使用工厂。工厂将抽象创建过程,这将使您的实体代码变得简单。

在DDD中,工厂对于创建聚合非常有用。在蓝皮书中有一整章关于工厂,这里有关于在DDD中使用工厂的好文章http://culttt.com/2014/12/24/factories-domain-driven-design/

修改

  

我的疑问是:这样可以吗? (传递给构造函数的DeliveryDate对象)或者我应该传递字符串? (并且构造函数创建DeliveryDate对象)

是的,没关系。任务不应该知道如何创建值对象。您不应该传递字符串,因为这会给Task构造函数增加更多的复杂性和责任。

  

我认为这更像是一个问题“聚合体外部是否应该了解DeliveryDate概念?”

是的,聚合外部知道DeliveryDate不是问题。它与了解字符串和整数相同。值对象很容易处理和推理,并且它们是域的一部分,所以我认为在聚合之外处理它们没有问题。

  

聚合工厂参数应该是值对象吗?或者用于创建值对象的基元?

这里我要说Factory应该接收原始类型并封装对象创建。因为如果你将values对象传递给工厂,它只会将相同的参数传递给Entity构造函数,那就是middleman code smell