领域驱动设计(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】全网最详细2万字讲解DDD,从理论到实战(代码示例) 3
【DDD】全网最详细2万字讲解DDD,从理论到实战(代码示例)
5189 2
|
领域建模
架构设计 DDD领域建模 核心概念
【1月更文挑战第6天】架构设计 DDD领域建模 核心概念
|
领域建模 数据库 数据安全/隐私保护
DailyMart03:如何基于DDD设计商城的领域模型?
DailyMart03:如何基于DDD设计商城的领域模型?
1395 0
|
消息中间件 网络协议 前端开发
殷浩详解DDD:如何避免写流水账代码?
在日常工作中我观察到,面对老系统重构和迁移场景,有大量代码属于流水账代码,通常能看到开发在对外的API接口里直接写业务逻辑代码,或者在一个服务里大量的堆接口,导致业务逻辑实际无法收敛,接口复用性比较差。所以本文主要想系统性的解释一下如何通过DDD的重构,将原有的流水账代码改造为逻辑清晰、职责分明的模块。
殷浩详解DDD:如何避免写流水账代码?
|
存储 自然语言处理 前端开发
领域驱动设计(DDD)-基础思想
一、序言     领域驱动设计是一种解决业务复杂性的设计思想,不是一种标准规则的解决方法。在领域驱动设计理念上,各路大侠的观点也是各有不同,能力有限、欢迎留言讨论。 二、领域驱动设计 DDD是什么 wiki释义:     领域驱动设计(英语:Domain-driven design,缩写 DDD)是一种通过将实现连接到持续进化的模型[1]来满足复杂
7789 0
|
设计模式 弹性计算 人工智能
阿里技术专家详解DDD系列 第四讲 - 领域层设计规范
在一个DDD架构设计中,领域层的设计合理性会直接影响整个架构的代码结构以及应用层、基础设施层的设计。但是领域层设计又是有挑战的任务,特别是在一个业务逻辑相对复杂应用中,每一个业务规则是应该放在Entity、ValueObject 还是 DomainService是值得用心思考的,既要避免未来的扩展性差,又要确保不会过度设计导致复杂性。
|
10月前
|
存储 设计模式 数据可视化
DDD新手入门:领域模型设计的七个核心概念
小米,29岁程序员,分享领域模型落地知识。文章解析领域、子域、限界上下文、领域对象、聚合、工厂与仓库等概念,助你理解领域驱动设计。
512 1
|
11月前
|
数据建模 程序员 数据库
领域设计之理解聚合与聚合根!
领域设计之理解聚合与聚合根!
180 1
领域设计之理解聚合与聚合根!
|
存储 测试技术 数据库
仓储设计实现问题之聚合实体在DDD中定义如何解决
仓储设计实现问题之聚合实体在DDD中定义如何解决
126 0
|
存储 消息中间件 JSON
DDD基础教程:一文带你读懂DDD分层架构
DDD基础教程:一文带你读懂DDD分层架构