Ben*_*ter 3 domain-driven-design
在一个应用程序中,我们建模Company为一个实体和Address一个值对象:
public class Company : Entity {
public Address PrimaryAddress { get; set; }
public Address SecondaryAddress { get; set; }
}
public class Address : ValueObject {
public string ZipCode { get; private set; } // etc.
public Address(string zipCode) {
ZipCode = zipCode;
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,Address没有身份并且是不可变的。为了更新PrimaryAddress公司,我用一个新Address对象替换它。
但是,在进一步发现域后,我们发现公司可能拥有可变数量的地址。将它们表示为单独的属性不再可行。所以我们重构了Company:
public class Company : Entity {
public Address[] AddressBook { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我们现在有一个问题是如何更新公司的Address. 我们现在关心地址的身份,但只在 Company 的上下文中。
重构后,我们最终得到:
public class Company : Entity {
public Address[] AddressBook { get; set; }
public void UpdateAddress(Address newAddress) {
var oldAddress = AddressBook.FirstOrDefault(a => a.Id == newAddress.Id);
if (oldAddress != null)
oldAddress = newAddress;
}
}
public class Address : ValueObject {
public Guid Id { get; private set; }
public string ZipCode { get; private set; } // etc.
public Address(Guid id, string zipCode) {
ZipCode = zipCode;
Id = id;
}
}
// usage
var company = repo.Load<Company>(companyId);
var address = new Address(model.Id, "12345"); // uses id of address we are replacing
company.UpdateAddress(address);
repo.Save(company);
Run Code Online (Sandbox Code Playgroud)
为了更新一个地址,我们使用它来定位它Id,并用一个具有相同Id的新地址对象替换它。
因此 Address 仍然是一个值对象吗?
我会说不,只要你给地址一个身份,它就不再是一个价值对象。这意味着您不再只关心它的属性,而是开始重视应用程序中的 Address 生命周期,跟踪其状态的变化等。
我对更新后的地址使用相同的 Id 是否正确,或者根据定义(作为值对象)我们是否应该替换 Id。
我不会重复使用地址 ID。从域的角度来看,当公司搬迁时,地址本身不会发生变化。该地址仍将有有效的街道号码和建筑物。该身份定义的地址仍然具有现实意义,您甚至可以想象将其重用于其他公司。因此,当公司搬迁时,只有公司和地址之间的关联需要更改以指向具有新 ID 的新地址。
如果 Address 仅在 Company 实体的上下文中具有标识,我们是否应该在我们的模型中明确表示这一点,也许生成一个仅在实体内部唯一的 Id(可能使用实体的 id 作为计算的一部分)?
仅仅因为您觉得需要在公司内挑选出不同的地址并不意味着您必须给它们一个 Id 并使它们成为实体而不是值对象。例如,如果您想对公司内部的地址进行排名,定义一个主要地址等,您可以使用值对象完美地做到这一点。地址值对象将保持不变,您可以在 Company 中拥有一个索引集合、一个 PrimaryAddress 字段等。