1. 引言
Ordering microservice(订单微服务)就是处理订单的了,它与前面讲到的几个微服务相比要复杂的多。主要涉及以下业务逻辑:
- 订单的创建、取消、支付、发货
- 库存的扣减
2. 架构模式

如上图所示,该服务基于CQRS 和DDD来实现。

从项目结构来看,主要包括7个项目:
- Ordering.API:应用层
- Ordering.Domain:领域层
- Ordering.Infrastructure:基础设施层
- Ordering.BackgroundTasks:后台任务
- Ordering.SignalrHub:基于Signalr的消息推送和实时通信
- Ordering.FunctionalTests:功能测试项目
- Ordering.UnitTests:单元测试项目
从以上的项目定义来看,该微服务的设计并符合DDD经典的四层架构。

核心技术选型:
- ASP.NET Core Web API
- Entity Framework Core
- SQL Server
- Swashbuckle(可选)
- Autofac
- Eventbus
- MediatR
- SignalR
- Dapper
- Polly
- FluentValidator
3. 简明DDD
领域驱动设计是一种方法论,用于解决软件复杂度问题。它强调以领域为核心驱动设计。主要包括战略和战术设计两大部分,其中战略设计指导我们在宏观层面对问题域进行识别和划分,从而将大问题划分为多个小问题,分而治之。而战术设计从微观层面指导我们如何对领域进行建模。
其中战术设计了引入了很多核心要素,指导我们建模:
- 值对象(Value Object)
- 实体(Entity)
- 领域服务(Domain Service)
- 领域事件(Domain Event)
- 资源库(Repository)
- 工厂(Factory)
- 聚合(Aggregate)
- 应用服务(Application Service)

其中实体、值对象和领域服务用于表示领域模型,来实现领域逻辑。
聚合用于封装一到多个实体和值对象,确保业务完整性。
领域事件来丰富领域对象之间的交互。
工厂、资源库用于管理领域对象的生命周期。
应用服务是用来表达用例和用户故事。
有了以上的战术设计要素还不够,如果它们糅合在一起,还是会很混乱,因此DDD再通过分层架构来确保关注点分离,即将领域模型相关(实体、值对象、聚合、领域服务、领域事件)放到领域层,将资源库、工厂放到基础设施层,将应用服务放到应用层。以下就是DDD经典的四层架构:
如果对订单微服务应用DDD,那么要摒弃传统的面向数据库建模的思想,转向领域建模。该项目中主要定义了以下领域对象:
- Order:订单
- OrderItem:订单项
- OrderStatus:订单状态
- Buyer:买家
- Address:地址
- PaymentMethod:支付方式
- CardType:银行卡片类型
在该示例项目中,定义了两个聚合:订单聚合和买家聚合,其中Order和Buyer分属两个聚合根,其中订单聚合通过持有买家聚合的唯一ID进行关联。如下图所示:
我们依次来看其对实体、值对象、聚合、资源库、领域事件的实现方式。
4.1. 实体、值对象与聚合

实体与值对象最大的区别在于,实体有标识符可变,值对象不可变。为了保证领域的不变性,也就是更好的封装,所有的属性字段都设置为private set,集合都设置为只读的,通过构造函数进行初始化,通过暴露方法供外部调用修改。
从类图中我们可以看出,其主要定义了一个Entity抽象基类,所有的实体通过继承Entity来实现命名约定。这里面有两点需要说明:
- 通过
Id属性确保唯一标识符 - 重写
Equals和GetHashCode方法(hash值计算:this.Id.GetHashCode() ^ 31) - 定义
DomainEvents来存储实体关联的领域事件(领域事件的发生归根结底是由于领域对象的状态变化引起的,而领域对象[实体、值对象和聚合])中值对象是不可变的,而聚合往往包含多个实体,所以将领域事件关联在实体上最合适不过。)

同样,值对象也是通过继承抽象基类ValueObject来进行约定。其主要也是重载了Equals和GetHashCode和方法。这里面有必要学习其GetHashCode的实现技巧:
