Logo
Section 1 / 5

实体

了解什么是实体,以及在领域驱动设计(DDD)中如何实现实体。

导入

实体

了解什么是实体,以及在领域驱动设计(DDD)中如何实现实体。

对领域进行建模可能十分困难。当整个模型完成后,下一步便是进入编码阶段。将领域模型转化为代码的最佳方式是采用面向对象编程(OOP)。为了实现这一方法,领域驱动设计(DDD)定义了一系列技术构件,使技术人员能够在代码中准确表达领域模型。

什么是模型驱动设计?

模型驱动设计(MDD) 指的是软件解决方案应基于对模型的分析来进行实现。请记住,模型是对现实世界中事物的抽象和表示,有助于我们更好地理解复杂系统。一旦完成了领域的建模,就可以开始软件的实现工作。

除了 MDD 方法论之外,对象管理组织(OMG) 还提出了一个名为 模型驱动架构(MDA) 的概念框架。MDA 提供了如何将用模型表达的软件需求进行结构化设计的指导原则,覆盖了从分析、设计、编程、测试、部署到维护的完整开发生命周期。MDA 使用三种模型:

  1. 计算无关模型(CIM):该模型聚焦于领域模型本身。
  2. 平台无关模型(PIM):该模型关注通用平台,即解决方案所部署的抽象平台环境。
  3. 平台特定模型(PSM):该模型针对具体的运行平台,描述在特定技术栈上的实现细节。

在 DDD 中什么是实体?

根据模型驱动设计的思想,DDD 使用战术设计模式来表达模型。用于实现业务逻辑的领域对象有三种:实体(Entity)、值对象(Value Object) 和 聚合(Aggregate)。

在 DDD 的语境中,实体代表参与业务流程中的某个事物。例如,在银行系统中,一些实体可能包括账户(Account)、信用卡(Credit Card)、客户(Customer)或交易(Transaction)。实体具有明确的属性和领域行为,并通过某种唯一标识(如 ID 或主键)来识别。这意味着即使其属性值发生变化,该对象的身份仍然保持不变,因此这类领域对象是可变的,但其身份不会因属性变化而受影响。

...
两个相似的实体

实体的特征

要正确定义一个实体,必须满足以下特征:

  • 每个实体都需要一个唯一标识符,且应在特定的限界上下文中定义。
  • 实体的意义应仅局限于一个限界上下文内。
  • 不应使用 setter 方法来修改状态。
  • 在必要时可以提供 getter 方法访问属性。
  • 若需封装逻辑,可通过值对象来承载部分行为。
  • 创建实体的唯一途径应是通过构造函数。

实体示例

假设需要实现跨两家银行之间的转账功能。在此场景下,需遵循如下业务规则:

  • 转账金额必须小于 10000。
  • 转账日期必须为当前日期。

对应的模型如下所示:

...
实体 Transfer

为此创建一个 Transfer 实体,用以封装相关业务逻辑。为测试该实体,编写一个 main 方法。根据 Transfer 的构造函数,main 方法传入 id、当前日期 date、amount 和 accountId 来创建一个 Transfer 对象。随后调用以下方法:

  • IsAmountLimitAllowed():若金额超过 10000,则输出 Amount is not allowed。
  • IsDateAllowed():若传入日期为当前日期,则输出 Date is allowed。

运行以下代码可观察实际执行过程。

Go

1package main 2 3import "time" 4 5// Transfer 包含转账实体的属性 6type Transfer struct { 7 id string 8 date time.Time 9 amount float64 10 accountId int64 11} 12 13// NewTransfer 是创建转账实体的唯一方式 14func NewTransfer(id string, date time.Time, amount float64, accountId int64) *Transfer{ 15 return &Transfer{ 16 id: id, 17 date: date, 18 amount: amount, 19 accountId: accountId, 20 } 21} 22 23// IsAmountLimitAllowed 检查转账金额是否超出银行限制 24func (t *Transfer) IsAmountLimitAllowed() bool{ 25 if t.amount >= 10000{ 26 return false 27 } 28 return true 29} 30 31// IsDateAllowed 检查转账是否发生在当天 32func (t *Transfer) IsDateAllowed() bool{ 33 now := time.Now() 34 if t.date.After(now){ 35 return false 36 } 37 return true 38}

Java

1import java.util.Date; 2 3// Transfer 是包含转账相关信息和逻辑的实体类 4public class Transfer { 5 6 // 转账实体的属性 7 private String id; 8 private Date date; 9 private Double amount; 10 private Long accountId; 11 12 // 构造函数是创建转账实体的唯一方式 13 public Transfer(String id, Date date, Double amount, Long accountId){ 14 this.id = id; 15 this.date = date; 16 this.amount = amount; 17 this.accountId = accountId; 18 } 19 20 // isAmountLimitAllowed 检查转账金额是否超出银行限额 21 public boolean isAmountLimitAllowed(){ 22 if(this.amount >= 10000) 23 return false; 24 return true; 25 } 26 27 // isDateAllowed 检查转账是否发生在当前日期 28 public boolean isDateAllowed(){ 29 Date now = new Date(); 30 if(this.date.after(now)){ 31 return false; 32 } 33 return true; 34 } 35}

总结

在 DDD 中,实体是一种通过唯一标识(ID)来区分的领域对象,它可以包含属性和业务逻辑。

领域活动

值对象