Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >泣血之作——初级领域设计详解,附带案例与代码

泣血之作——初级领域设计详解,附带案例与代码

原创
作者头像
裕贞
发布于 2025-02-17 05:45:32
发布于 2025-02-17 05:45:32
680
举报

一、核心理论概念

1.1 领域设计三大支柱

代码语言:mermaid
AI代码解释
复制
graph TD 
    A[战略设计] --> B(限界上下文)
    A --> C(上下文映射)
    D[战术设计] --> E(实体)
    D --> F(值对象)
    D --> G(聚合根)
    H[实现模式] --> I(仓储模式)
    H --> J(领域服务)

1.2 核心要素说明

概念

特征

示例

实体

唯一标识,可变状态

订单(Order)

值对象

不可变,无标识

金额(Money)

聚合根

业务一致性边界

订单聚合根

领域服务

处理跨聚合的业务逻辑

订单服务

二、电商订单系统案例

2.1 业务场景描述

需求:实现电商订单创建与库存扣减的原子操作

业务规则:

  1. 订单金额必须大于0
  2. 库存不足时禁止下单
  3. 订单状态需按流程流转(创建→已支付→已完成)

2.2 领域模型设计

代码语言:java
AI代码解释
复制
// 值对象示例 
public record Money(BigDecimal amount, Currency currency) {
    public Money {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("金额必须大于0");
        }
    }
}
 
// 实体示例 
public class OrderItem {
    private final String productId;
    private final int quantity;
    private final Money price;
    
    // 构造函数与业务方法省略...
}
 
// 聚合根示例 
public class Order {
    private String orderId;
    private List<OrderItem> items;
    private OrderStatus status;
    
    public void confirmPayment() {
        if (status != OrderStatus.CREATED) {
            throw new IllegalStateException("订单状态异常");
        }
        status = OrderStatus.PAID;
    }
}

三、完整Java实现

3.1 项目结构

代码语言:txt
AI代码解释
复制
src/main/java/com/example/ddd/
├── model 
│   ├── Order.java          # 聚合根 
│   ├── OrderItem.java      # 实体 
│   └── Money.java          # 值对象 
├── service 
│   └── OrderService.java   # 领域服务 
└── repository 
    └── InventoryRepo.java  # 仓储接口 

3.2 代码类图

代码语言:mermaid
AI代码解释
复制
classDiagram 
    class Money {
        <<Value Object>>
        -BigDecimal amount 
        -Currency currency 
        +Money(BigDecimal, Currency)
        +add(Money) Money 
        +multiply(int) Money 
    }
 
    class OrderItem {
        <<Entity>>
        -String productId 
        -int quantity 
        -Money price 
        +OrderItem(String, int, Money)
        +productId() String 
        +quantity() int 
        +price() Money 
    }
 
    class Order {
        <<Aggregate Root>>
        -String orderId 
        -List<OrderItem> items 
        -OrderStatus status 
        -LocalDateTime createTime 
        +Order(String, List~OrderItem~)
        +confirmPayment() void 
        +calculateTotal() BigDecimal 
        +getDomainEvents() List~DomainEvent~
    }
 
    class OrderService {
        <<Domain Service>>
        -InventoryRepository inventoryRepo 
        +placeOrder(List~OrderItem~) Order 
    }
 
    class InventoryRepository {
        <<Repository Interface>>
        +getStock(String) int 
        +reduceStock(String, int) void 
        +addStock(String, int) void 
    }
 
    class OrderStatus {
        <<Enumeration>>
        CREATED 
        PAID 
        COMPLETED 
        CANCELLED 
    }
 
    Order "1" *-- "*" OrderItem : contains 
    OrderItem "1" -- "1" Money : uses 
    OrderService ..> InventoryRepository : depends 
    OrderService ..> Order : creates 
    OrderStatus <.. Order : uses 

3.3 核心代码实现

值对象(Money)

代码语言:java
AI代码解释
复制
public record Money(BigDecimal amount, Currency currency) implements Serializable {
    
    public Money add(Money other) {
        if (!currency.equals(other.currency)) {
            throw new CurrencyMismatchException();
        }
        return new Money(amount.add(other.amount), currency);
    }
    
    public Money multiply(int quantity) {
        return new Money(amount.multiply(BigDecimal.valueOf(quantity)), currency);
    }
}

聚合根(Order)

代码语言:java
AI代码解释
复制
public class Order {
    private String orderId;
    private List<OrderItem> items;
    private OrderStatus status;
    private LocalDateTime createTime;
 
    public Order(String orderId, List<OrderItem> items) {
        this.orderId = Objects.requireNonNull(orderId);
        this.items = new ArrayList<>(Objects.requireNonNull(items));
        this.status = OrderStatus.CREATED;
        this.createTime = LocalDateTime.now();
    }
 
    public void confirmPayment() {
        if (status != OrderStatus.CREATED) {
            throw new IllegalOrderStateException();
        }
        status = OrderStatus.PAID;
    }
 
    public BigDecimal calculateTotal() {
        return items.stream()
                .map(item -> item.price().multiply(item.quantity()))
                .reduce(Money::add)
                .orElseThrow()
                .amount();
    }
}

领域服务(OrderService)

代码语言:java
AI代码解释
复制
public class OrderService {
    private final InventoryRepository inventoryRepo;
 
    public Order placeOrder(List<OrderItem> items) {
        // 库存检查 
        items.forEach(item -> {
            int available = inventoryRepo.getStock(item.productId());
            if (available < item.quantity()) {
                throw new InsufficientStockException();
            }
        });
 
        // 创建订单 
        Order newOrder = new Order(UUID.randomUUID().toString(), items);
        
        // 扣减库存 
        items.forEach(item -> 
            inventoryRepo.reduceStock(item.productId(), item.quantity()));
        
        return newOrder;
    }
}

四、案例分析与成果

4.1 设计分析

  1. 聚合边界控制:
    • Order作为聚合根,封装订单状态变更
    • 库存变更通过领域服务协调
  2. 业务规则内化:
代码语言:java
AI代码解释
复制
// 在Money值对象中内嵌验证规则 
public Money(BigDecimal amount, Currency currency) {
    if (amount.compareTo(BigDecimal.ZERO) <= 0) {
        throw new IllegalArgumentException("金额必须大于0");
    }
    this.amount = amount.setScale(2, RoundingMode.HALF_UP);
    this.currency = currency;
}
  1. 领域服务协调:
代码语言:txt
AI代码解释
复制
sequenceDiagram 
    participant Client 
    participant OrderService 
    participant InventoryRepo 
    participant Order 
    
    Client->>OrderService: placeOrder(items)
    OrderService->>InventoryRepo: getStock(productId)
    InventoryRepo-->>OrderService: stock 
    OrderService->>Order: new()
    OrderService->>InventoryRepo: reduceStock()
    OrderService-->>Client: return Order 

4.2 运行示例

代码语言:java
AI代码解释
复制
public class Application {
    public static void main(String[] args) {
        // 初始化仓储 
        InventoryRepository repo = new MemoryInventoryRepo();
        repo.addStock("P1001", 10);
        
        // 创建订单项 
        List<OrderItem> items = List.of(
            new OrderItem("P1001", 2, new Money(new BigDecimal("99.99"), Currency.USD))
        );
        
        // 执行下单 
        OrderService service = new OrderService(repo);
        Order order = service.placeOrder(items);
        
        System.out.println("订单创建成功:" + order);
        System.out.println("当前库存:" + repo.getStock("P1001"));
    }
}
 
// 输出结果:
// 订单创建成功:Order[total=199.98 USD]
// 当前库存:8 

五、设计总结

5.1 关键收益

  • 业务显性化:订单状态机直接反映业务规则
  • 可维护性:库存管理逻辑集中处理
  • 可测试性:领域对象可独立单元测试

5.2 改进方向

  1. 引入领域事件(如OrderPlacedEvent)
  2. 实现真正的持久化仓储
  3. 增加分布式事务处理
  4. 实施CQRS模式分离读写操作
代码语言:java
AI代码解释
复制
// 改进示例:领域事件发布 
public class Order {
    // ...
    private List<DomainEvent> domainEvents = new ArrayList<>();
    
    public void confirmPayment() {
        // ...原有逻辑...
        domainEvents.add(new OrderPaidEvent(this.orderId));
    }
    
    public List<DomainEvent> getDomainEvents() {
        return Collections.unmodifiableList(domainEvents);
    }
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
后端开发实践系列——领域驱动设计(DDD)编码实践
的确,很多时候软件的业务逻辑是无法通过推理而得到的,有时甚至是被臆想出来的。这样的结果使得原本已经很复杂的业务变得更加复杂而难以理解。而在具体编码实现时,除了应付业务上的复杂性,技术上的复杂性也不能忽略,比如我们要讲究技术上的分层,要遵循软件开发的基本原则,又比如要考虑到性能和安全等等。
ThoughtWorks
2019/08/01
1.4K0
后端开发实践系列——领域驱动设计(DDD)编码实践
DDD模型初探
聚合根: 它是一个实体对象,代表了一个业务上的整体,它可以包含多个实体对象和值对象。聚合根负责维护整个聚合内部的一致性,所有对聚合内部的操作都必须通过聚合根进行。在实现订单管理功能时,我们可以使用聚合根来维护订单和订单项之间的关系。
灬沙师弟
2023/09/06
4020
DDD模型初探
常用23种设计模式Java经典实现(使用常用电商业务订单、购物车,商户,支付,优惠券为例)
定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类。
jack.yang
2025/04/05
1480
📖  《代码重构的独孤九剑:如何优雅改造祖传屎山代码》
当代码库膨胀至百万行级别时,常见的Controller-Service-DAO分层模式会演变为:
Jimaks
2025/04/29
1510
DDD实践原则规范
领域驱动设计(Domain-Driven Design,DDD)是一种软件开发方法论,旨在将软件系统的设计与业务领域的实际需求相结合。在DDD中,设计和开发围绕着领域模型展开,以解决复杂业务问题和满足业务需求。本文将介绍DDD实践原则规范,包括聚合根、实体与值对象、资源库、工厂、领域服务、命令对象、业务中读写操作以及与工具技术结合使用原则。
疯狂的KK
2023/07/28
7870
DDD实践原则规范
Java流对象stream的map方法详解
Java 流对象 Stream 的 map 方法是 Stream API 中一个非常核心且强大的功能,它允许对流中的每个元素应用一个函数,将其转换为另一种类型的元素。下面我将从定义、用途、应用范围以及详细示例等方面对 map 方法进行详解。
jack.yang
2025/04/05
3920
《解构领域驱动设计》勘误
本书从出版以来,已经先后印刷7次。感谢广大读者书友,友善地帮我找到了一些bug,并前后做了两次勘误。
张逸
2023/03/23
7650
《解构领域驱动设计》勘误
如何一步一步用DDD设计一个电商网站(十三)—— 领域事件扩展
上篇中我们初步运用了领域事件,其中还有一些问题我们没有解决,所以实现是不健壮的,下面先来回顾一下。
Zachary_ZF
2018/09/10
1.1K0
如何一步一步用DDD设计一个电商网站(十三)—— 领域事件扩展
MassTransit | 基于StateMachine实现Saga编排式分布式事务
状态机作为一种程序开发范例,在实际的应用开发中有很多的应用场景,其中.NET 中的async/await 的核心底层实现就是基于状态机机制。状态机分为两种:有限状态机和无限状态机,本文介绍的就是有限状态机,有限状态机在任何时候都可以准确地处于有限状态中的一种,其可以根据一些输入从一个状态转换到另一个状态。一个有限状态机是由其状态列表、初始状态和触发每个转换的输入来定义的。如下图展示的就是一个闸机的状态机示意图:
圣杰
2023/01/31
1.3K1
深入理解设计模式:23种经典模式全解析与应用示例
设计模式是一组用于解决特定类型软件设计问题的解决方案。它们提供了一种抽象的方式来表达应用程序中常见问题的解决方案,帮助开发者更有效地解决问题,提高开发效率,降低开发成本,提高代码质量和可维护性,以及更好地管理和理解复杂的系统。
jack.yang
2025/04/10
3760
SSM综合案例 订单案例查询功能实现
张哥编程
2024/12/13
1150
关于聚合根、领域事件的那点事——深入浅出理解DDD
Tech 导读 领域驱动设计(Domain-Driven Design,简称DDD)是一种软件开发方法论,旨在帮助开发人员更好地理解和解决复杂领域的问题。在DDD中,聚合根和领域事件是两个核心概念,它们在设计和实现领域模型时起到了重要的作用。本文将通过简单的举例方式,深入浅出地介绍聚合根和领域事件,帮助读者更好地理解DDD的核心思想和实践方法。希望本文能够为读者提供有价值的知识和启发,帮助大家在软件开发中更好地应用DDD的思想和方法。
京东技术
2023/08/22
1.5K0
关于聚合根、领域事件的那点事——深入浅出理解DDD
DDD之Repository对象生命周期管理
在DDD中Repository是一个相当重要的概念。聚合是战略与战术之间的交汇点。而管理聚合的正是Repository。
码农戏码
2022/11/18
7630
DDD之Repository对象生命周期管理
day02_springboot综合案例
张哥编程
2024/12/13
730
day02_springboot综合案例
Table-values parameter(TVP)系列之三: 利用Collection将其作为参数传给SP
一,回顾 上一部分讲述了“在ADO.NET中利用DataTable对象,将其作为参数传给存贮过程”。 通过DataTable实例,完成了两部分的内容:   1)DataTable的数据传输给Stored Procedure   2)利用DataTable的TVP数据,可以参与别的实体数据读写(DataReader)。 这一部分的内容,通过Collection对象,还是要实现上边的两个实例。 二,在ADO.NET中利用Collection对象,将其作为参数传给存贮过程   通过
葡萄城控件
2018/01/10
4940
领域驱动设计简介(下篇)
正如我们已经指出的那样,大多数DDD系统可能会使用OO范例。因此,我们对领域模型的元素可能很熟悉,例如实体,值对象和模块。例如,如果您是Java程序员,那么将DDD实体视为与JPA实体基本相同(使用@Entity注释)就足够安全了。
lyb-geek
2022/03/10
5570
领域驱动设计简介(下篇)
译:持久化DDD聚合
原文链接:https://www.baeldung.com/spring-persisting-ddd-aggregates
用户1516716
2018/12/24
1.8K0
捣鼓一个电商功能设计
谷歌系统设计面试有一道题是关于如何设计秒杀架构,国外一位老哥给出了5种方法,下图是其中一种。
JavaSouth南哥
2024/10/16
1770
捣鼓一个电商功能设计
jeecgboot集成seata实战
采用jeecg-boot单体模式测试,使用默认的文件进行seata配置,不需要做额外的配置,直接启动seata-server.bat即可。
JEECG
2022/04/25
5890
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合!
随着云计算、微服务和大数据技术的快速发展,构建可扩展、高性能和弹性的应用程序变得越来越重要。为了满足这些要求,许多开发人员转向了事件驱动架构,它允许应用程序通过基于事件的方式相互通信,从而提高了系统的响应速度和伸缩性。在这个背景下,Spring Cloud Stream应运而生,它是一个用于构建基于事件驱动的微服务应用程序的框架,可以与现有的消息中间件(如Apache Kafka和RabbitMQ)无缝集成。
苏泽
2024/03/10
3680
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合!
推荐阅读
相关推荐
后端开发实践系列——领域驱动设计(DDD)编码实践
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档