领域驱动设计(DDD)中的实体,值对象,和聚合

简介: 领域驱动设计(DDD)中的实体,值对象,和聚合

引言

在我们的软件开发旅程中,我们常常会遇到复杂的业务问题。为了解决这些问题,我们需要一种方法来更好地理解和组织我们的代码。这就是领域驱动设计(DDD)的来源。在本文中,我们将深入探讨DDD中的三个关键概念:实体,值对象,和聚合,并通过实际的案例来展示它们在实际项目中的应用和效果。

实体

实体是DDD中的一个核心概念。它是一个具有唯一标识符的对象,这意味着即使两个实体的属性完全相同,只要它们的标识符不同,它们就是不同的实体。这个特性使得我们可以跟踪和管理实体的生命周期。

例如,在一个电商系统中,每个用户都可以被视为一个实体。即使两个用户的所有信息(如姓名,地址,电话等)都相同,只要他们的用户ID不同,他们就是两个不同的实体。这种设计使得我们可以轻松地跟踪用户的行为,例如购物历史,购物车状态等。

值对象

值对象是另一个重要的DDD概念。与实体不同,值对象没有唯一标识符,它们的相等性是通过它们的属性来确定的。如果两个值对象的所有属性都相同,那么它们就是相等的。

例如,我们可以将地址视为一个值对象。如果两个地址对象的所有属性(如街道,城市,邮编等)都相同,那么我们可以认为这两个地址是相同的。这种设计使得我们可以在不同的上下文中重用地址对象,例如用户的收货地址,发票地址等。

聚合

聚合是一种特殊的实体,它包含了其他的实体和值对象。聚合的主要目的是保证业务规则的一致性。在聚合内部,所有的对象都是一起工作的,它们共享同一个生命周期。

例如,在一个订单系统中,一个订单可以被视为一个聚合。订单包含了多个订单项(实体)和一个地址(值对象)。当我们修改订单时,我们需要确保所有的订单项和地址都满足业务规则。例如,我们不能添加一个已经停产的商品到订单中,我们不能将订单发送到一个无效的地址。

实际案例

让我们通过一个实际的案例来看看这些概念是如何在实际的项目中应用的。

订单系统

在一个电商系统中,我们可以创建一个订单聚合。订单聚合包含了订单实体和多个订单项实体,以及一个地址值对象。订单实体有一个唯一的订单ID,订单项实体有一个唯一的订单项ID,地址值对象则没有唯一标识符。

当用户添加一个商品到购物车时,我们会创建一个新的订单项实体,并将它添加到订单聚合中。当用户更改收货地址时,我们会更新订单聚合中的地址值对象。所有这些操作都需要通过订单聚合来完成,以确保业务规则的一致性。

例如,我们不能添加一个已经停产的商品到订单中,我们不能将订单发送到一个无效的地址。这些业务规则都是由订单聚合来保证的。

诊所系统

在一个诊所系统中,我们可以创建一个诊所访问聚合。诊所访问聚合包含了诊所访问实体和多个诊疗项目实体,以及一个患者实体。诊所访问实体有一个唯一的访问ID,诊疗项目实体有一个唯一的项目ID,患者实体有一个唯一的患者ID。

当患者预约一个诊疗项目时,我们会创建一个新的诊疗项目实体,并将它添加到诊所访问聚合中。当患者更改预约时间时,我们会更新诊所访问聚合中的诊所访问实体。所有这些操作都需要通过诊所访问聚合来完成,以确保业务规则的一致性。

例如,我们不能预约一个已经满员的诊疗项目,我们不能预约一个已经过去的时间。这些业务规则都是由诊所访问聚合来保证的。

以下是一个简单的诊所系统的代码示例,使用了DDD的实体,值对象和聚合的概念。这个示例是用Java编写的,但是你可以根据你的需要将其转换为其他编程语言。

// 实体
public class Patient {
    private String patientId;
    private String name;
    public Patient(String patientId, String name) {
        this.patientId = patientId;
        this.name = name;
    }
    // getters and setters
}
// 值对象
public class AppointmentTime {
    private LocalDateTime time;
    public AppointmentTime(LocalDateTime time) {
        this.time = time;
    }
    // getters and setters
}
// 实体
public class Treatment {
    private String treatmentId;
    private String name;
    private AppointmentTime appointmentTime;
    public Treatment(String treatmentId, String name, AppointmentTime appointmentTime) {
        this.treatmentId = treatmentId;
        this.name = name;
        this.appointmentTime = appointmentTime;
    }
    // getters and setters
}
// 聚合
public class ClinicVisit {
    private String visitId;
    private Patient patient;
    private List<Treatment> treatments;
    public ClinicVisit(String visitId, Patient patient) {
        this.visitId = visitId;
        this.patient = patient;
        this.treatments = new ArrayList<>();
    }
    public void addTreatment(Treatment treatment) {
        // 添加业务规则,例如检查预约时间是否已过,诊疗项目是否已满员等
        this.treatments.add(treatment);
    }
    // getters and setters
}
相关文章
|
领域建模
架构设计 DDD领域建模 核心概念
【1月更文挑战第6天】架构设计 DDD领域建模 核心概念
|
设计模式 前端开发 关系型数据库
【DDD】全网最详细2万字讲解DDD,从理论到实战(代码示例) 3
【DDD】全网最详细2万字讲解DDD,从理论到实战(代码示例)
6028 2
|
存储 关系型数据库 数据库
聊多版本并发控制(MVCC)
MVCC是数据库并发控制技术,用于减少读写冲突。它维护数据的多个版本,使事务能读旧数据而写新数据,无需锁定记录。当前读获取最新版本,加锁防止修改;快照读不加锁,根据读取时的读视图(readview)决定读哪个版本。InnoDB通过隐藏字段(DB_TRX_ID, DB_ROLL_PTR)和undo log存储版本,readview记录活跃事务ID。读已提交每次读取都创建新视图,可重复读则在整个事务中复用一个视图,确保一致性。MVCC通过undo log版本链和readview规则决定事务可见性,实现了非阻塞并发读。
1405 5
聊多版本并发控制(MVCC)
|
设计模式 JSON 架构师
你真的需要防腐层吗?DDD 系统间的7种关系梳理与实践
当提到系统间交互的时候,人们都会想到大名鼎鼎的防腐层,用来防止其他系统的模型变更对本系统造成影响。但是在实践这个模式的过程中,我们常常会遇到问题。此时我们也应该考虑下其他的系统交互方式。
28209 12
你真的需要防腐层吗?DDD 系统间的7种关系梳理与实践
|
SQL 缓存 Java
殷浩详解DDD系列 第三讲 - Repository模式
# 第三讲 - Repository模式 **写在前面** 这篇文章和上一篇隔了比较久,一方面是工作比较忙,另一方面是在讲Repository之前其实应该先讲Entity(实体)、Aggregate Root(聚合根)、Bounded Context(限界上下文)等概念。但在实际写的过程中,发现单纯讲Entity相关的东西会比较抽象,很难落地。所以本文被推倒重来,从Repository
38755 8
|
前端开发 测试技术 API
DDD领域驱动设计实战-分层架构及代码目录结构(上)
DDD领域驱动设计实战-分层架构及代码目录结构
2041 0
DDD领域驱动设计实战-分层架构及代码目录结构(上)
|
领域建模 数据库 数据安全/隐私保护
DailyMart03:如何基于DDD设计商城的领域模型?
DailyMart03:如何基于DDD设计商城的领域模型?
1589 0
|
存储 自然语言处理 前端开发
领域驱动设计(DDD)-基础思想
一、序言     领域驱动设计是一种解决业务复杂性的设计思想,不是一种标准规则的解决方法。在领域驱动设计理念上,各路大侠的观点也是各有不同,能力有限、欢迎留言讨论。 二、领域驱动设计 DDD是什么 wiki释义:     领域驱动设计(英语:Domain-driven design,缩写 DDD)是一种通过将实现连接到持续进化的模型[1]来满足复杂
8459 0
|
消息中间件 网络协议 前端开发
殷浩详解DDD:如何避免写流水账代码?
在日常工作中我观察到,面对老系统重构和迁移场景,有大量代码属于流水账代码,通常能看到开发在对外的API接口里直接写业务逻辑代码,或者在一个服务里大量的堆接口,导致业务逻辑实际无法收敛,接口复用性比较差。所以本文主要想系统性的解释一下如何通过DDD的重构,将原有的流水账代码改造为逻辑清晰、职责分明的模块。
殷浩详解DDD:如何避免写流水账代码?
|
存储 设计模式 数据可视化
DDD新手入门:领域模型设计的七个核心概念
小米,29岁程序员,分享领域模型落地知识。文章解析领域、子域、限界上下文、领域对象、聚合、工厂与仓库等概念,助你理解领域驱动设计。
1072 1

热门文章

最新文章