如果您有一个具有值对象的实体作为属性。
哪个是实体构造函数的参数,值对象?还是值对象的原始类型?
首先,我在实体外构建了值对象,然后将值对象传递给实体构造函数......但后来我意识到可能是实体本身必须构建值对象。
我认为这是因为实体和值对象实际上是一个聚合,并且假设您必须通过聚合根(即通过实体)访问聚合内部。
那么哪种方式正确?是否允许处理实体外的价值对象?或者值对象只能由实体使用?
谢谢。
修改
例如,我有一个实体“任务”,它是聚合根。该实体具有值对象“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(这只是一个例子)。
我已经提出了有关构造函数的问题,但它也适用于工厂(如果创建实例的过程很复杂)...聚合工厂参数应该是值对象吗?或者用于创建值对象的基元?
答案 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。