## 3.2 ABP领域层 - 值对象
### 3.2.1 简介
用来描述领域的特殊方面、且没有标识符的一个对象,叫做值对象。
实体有自己的唯一标识,而值对象是没有标识的。如果两个实体的标识是不同的,那么它们是两个不同的实体,即使这两个实体的其它属性值是相同的。想象一下两个不同的人但是他们有相同的姓和名以及年龄。但是,他们的标识是不同的话,那么他们就是不同的两个人。但是,对于地址(这是一个典型的值对象)类,如果这两个地址拥有相同的国家,城市,街道号等等。那么它们就是同一个地址。
在DDD中,值对象是领域对象的另一种类型,它可以包含业务逻辑并且是领域中不可或缺的一部分。
### 3.2.2 DDD中重要概念
#### 实体entity:
拥有唯一标识符一类对象,
但对象不是通过它们的属性定义的,而是通过一连串的连续性事件和标识定义的。
#### 值对象-value Object
+ 1.对某个对象是什么不感兴趣,只关心它拥有的属性
+ 2.用来描述领域的特殊方面、且没有标识符的一个对象,叫做值对象
+ 3.能被简单的创建和丢弃,生命周期中不会被持久化
+ 4.值对象可以被共享,值对象应该不可变
#### 服务-service(比webservice更细粒度服务描述)
+ 1.领域中的一些动词,代表了领域中的一个重要的行为,却不属于任何对象
+ 1)服务执行的操作涉及一个领域概念,这个领域概念通常不属于一个实体或者值对象
+ 2)被执行的操作涉及到领域中的其他的对象
+ 3)操作是无状态的
+ 2.服务对象不再拥有内置的状态
+ 3.服务对象担当重要的协调功能
+ 4.开发通用语言时,领域中的主要概念被引入到语言中,语言中的名词很容易被映射成对象。
语言中对应那些名词的动词变成那些对象的行为。但是有些领域中的动作,它们是一些动词,看上去却不属于任何对象。它们代表了领域中的一个重要的行为,所以不能忽略它们或者简单的把它们合并到某个实体或者值对象中。给一个对象增加这样的行为会破坏这个对象,让它看上去拥有了本该属于它的功能。
#### 模块
+ 1.将相关领域模型提炼分类,分而治之
+ 2.将高关联度的模型分组到一个模块以提供尽可能大的内聚(以能完整完成任务为准)
+ 3.分层是水平划分
+ 4.模块是垂直划分(Domain内部)
### 3.2.3 值对象基类
ABP有一个基类 **ValueObject\<T\>**,为了能够更方便的创建值对象,我们可以继承该基类。如:**Address** 值对象:
```csharp
public class Address : ValueObject<Address>
{
public Guid CityId { get; private set; } //对城市实体的引用
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;
}
}
```
值对象基类对==操作符进行了重写(还有其他相关的操作符和方法)来比较两个值对象是否相等,如果所有的属性的值都是相同的,那么断定这两个值对象相等。所以,如下测试是通过的:
```csharp
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);
```
即使它们在内存中是不同的对象,但是在领域中它们是相同的。
### 3.2.4 最佳实践
这里有一些对值对象设计建议:
+ 值对象应该被设计为不可变的(如上面的Address值对象)
+ 构成一个值对象的属性应该形成一个概念上的整体。例如:CityId,街道和号码不应该是构成Person实体的一部分,应该分离出来作为Address值对象。这样也使Person实体更简单。
- 文章&教程
- Abp
- 1.1ABP总体介绍-入门介绍
- 1.2ABP总体介绍-多层架构体系
- 1.3ABP总体介绍-模块系统
- 1.4ABP总体介绍-启动配置
- 1.5ABP总体介绍-多租户
- 1.6ABP总体介绍-集成OWIN
- 2.1ABP公共结构-依赖注入
- 2.2ABP公共结构-会话管理
- 2.3ABP公共结构-缓存管理
- 2.4ABP公共结构-日志管理
- 2.5ABP公共结构-设置管理
- 2.6ABP公共结构-时区设置
- 3.1ABP领域层-实体
- 3.2ABP领域层-值对象
- 3.3ABP领域层-仓储
- 3.4ABP领域层-领域服务
- 3.5ABP领域层-工作单元
- 3.6ABP领域层-领域事件
- 3.7ABP领域层-数据过滤器
- 4.1ABP应用层-应用服务
- 4.2ABP应用层-数据传输对象
- 4.3ABP应用层-数据传输对象验证
- 4.4ABP应用层-权限认证
- 4.5ABP应用层-功能管理
- 4.6ABP应用层-审计日志
- 5.1ABP分布式服务-ASP.NET WebApi
- 5.2ABP分布式服务-动态WebApi层
- 5.3ABP分布式服务-集成OData
- 5.4ABP分布式服务-集成SwaggerUI
- 6.1ABP表现层-Mvc控制器
- 6.2ABP表现层-Mvc视图
- 6.3ABP表现层-本地化
- 6.4ABP表现层-导航栏
- 6.5ABP表现层-异常处理
- 6.6.2-AJAX
- 6.6.3-Notification
- 6.6.4-Message
- 6.6.5-UIBlockBusy
- 6.6.6-EventBus
- 6.6.7-Logging
- 6.6.8-OtherUtilities
- 6.6ABP表现层-JavascriptAPI
- 6.7ABP表现层-嵌入资源文件
- 6.8ASP.NET-Core
- 6.9CSRF和XSRF保护
- 7.1ABP后台服务-后台作业和工人
- 7.2ABP后台服务-集成Hangfire
- 8.1ABP实时服务-通知系统
- 8.2ABP实时服务-集成SignalR
- 9.1ABP基础设施层-集成Entity Framework
- 9.2ABP基础设施层-集成NHibernate
- 9.3ABP基础设施层-集成Entity Framework Core
- abp合并版160929
- md文档排版规范
- AbpZero
- 1.1ABPZero-概述
- 1.2ABPZero-安装
- 1.3ABPZero-启动模板
- 1.4ABPZero-启动模板Core
- 2.1ABPZero-多租户管理
- 2.2ABPZero-版本管理
- 2.4ABPZero-组织单位管理