ABP官方文档翻译 3.2 值对象
值对象
"展现领域描述性层面且没有概念性身份的对象称之为值对象。"(Eric Evans)。
和实体相反,实体有身份标示(Id),值对象没有身份标示。如果两个实体的身份标示是不同的,那么就认为他们是不同的对象/实体,即使他们的所有属性都是一样的。考虑两个不同的人有相同的名字、姓氏和年龄,但是他们是不同的人,如果他们的身份编号不同的话。但是,对于一个地址(经典的值对象)类,如果两个地址有相同的国家、城市、街道编号等等,则认为为相同的地址。
在DDD中,值对象是领域对象的另一种类型,可以包含业务逻辑,是领域的重要组成部分。
ABP有一个ValueObject<T>基类,可以被继承用来轻松创建值对象类型。Address值对象类型示例如下:
public class Address : ValueObject<Address> { public Guid CityId { get; private set; } //A reference to a City entity. public string Street { get; private set; } public int Number { get; private set; } public Address(Guid cityId, string street, int number) { CityId = cityId; Street = street; Number = number; } }
值对象基类重写了等于操作符(还有其他相关的操作符和方法)来比较两个值对象,如果两个值对象所有的属性都相等则认为他们是相等的。所以,所有下面的测试都是通过的:
var address1 = new Address(new Guid("21C67A65-ED5A-4512-AA29-66308FAAB5AF"), "Baris Manco Street", 42); var address2 = new Address(new Guid("21C67A65-ED5A-4512-AA29-66308FAAB5AF"), "Baris Manco Street", 42); Assert.Equal(address1, address2); Assert.Equal(address1.GetHashCode(), address2.GetHashCode()); Assert.True(address1 == address2); Assert.False(address1 != address2);
即使在内存中是不同的对象,在我们的领域中也认为他们是完全相同的。
一些值对象的最佳实践:
- 将值对象设计为不可变的(如上面的Address类),如果没有好的理由将它设计为可变的话。
- 组成值对象的属性应形成一个概念上的整体。例如,CityId、Street和编号不应该是一个Person实体分离的属性。这也使得Person实体更简单。