领域驱动设计(DDD)四 订单管理系统实践步骤

深入浅出 “ 领域驱动设计(Domain-Driven Design, DDD)” 领域驱动设计(DDD)的概念很多,理解难度很大,但是抽丝剥茧后,发现殊途同归。 阅读详情

以下是基于 领域驱动设计(DDD) 的订单管理系统实践步骤,系统功能主要包括订单的创建、更新、查询和状态管理,采用 Spring Boot 框架进行实现。


1. 需求分析

订单管理系统的基本功能:

  1. 订单创建:用户下单创建订单。
  2. 订单状态更新:更新订单状态(如已支付、已发货、已完成)。
  3. 订单查询:支持按订单 ID 或用户查询订单信息。
  4. 库存管理(简化版):订单创建时检查并扣减库存。

2. 领域划分与限界上下文

限界上下文

  1. 订单上下文(Order Context):负责订单的生命周期管理。
  2. 库存上下文(Inventory Context):负责商品库存的管理。

模块划分

src/main/java/com/example/order
├── application         # 应用层:处理用例逻辑
│   ├── service         # 应用服务
│   └── dto             # 数据传输对象
├── domain              # 领域层:业务逻辑
│   ├── model           # 领域模型(实体、值对象、聚合)
│   ├── repository      # 仓储接口
│   ├── service         # 领域服务
│   └── event           # 领域事件
├── infrastructure      # 基础设施层:技术实现
│   ├── repository      # 仓储实现
│   └── event           # 事件机制
└── interfaces          # 接口层:用户交互
    ├── controller      # REST 接口
    └── vo              # 视图对象

3. 代码实现

3.1 领域层设计

领域模型

(1) 订单实体

public class Order {
    private Long id;                  // 订单ID
    private String customerId;        // 用户ID
    private List<OrderItem> items;    // 订单项
    private OrderStatus status;       // 订单状态

    // 创建订单
    public Order(String customerId, List<OrderItem> items) {
        this.customerId = customerId;
        this.items = items;
        this.status = OrderStatus.CREATED;
    }

    // 更新订单状态
    public void updateStatus(OrderStatus status) {
        if (this.status.canTransitionTo(status)) {
            this.status = status;
        } else {
            throw new IllegalStateException("非法状态转换");
        }
    }

    // 计算总金额
    public BigDecimal calculateTotal() {
        return items.stream()
                .map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())))
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    // Getters and Setters
}

(2) 订单项值对象

public class OrderItem {
    private Long productId;   // 商品ID
    private int quantity;     // 数量
    private BigDecimal price; // 单价

    // 构造方法
    public OrderItem(Long productId, int quantity, BigDecimal price) {
        this.productId = productId;
        this.quantity = quantity;
        this.price = price;
    }

    // Getters and Setters
}

(3) 订单状态值对象

public enum OrderStatus {
    CREATED, PAID, SHIPPED, COMPLETED;

    // 状态转换规则
    public boolean canTransitionTo(OrderStatus newStatus) {
        return switch (this) {
            case CREATED -> newStatus == PAID;
            case PAID -> newStatus == SHIPPED;
            case SHIPPED -> newStatus == COMPLETED;
            default -> false;
        };
    }
}

3.2 应用层设计

订单服务

@Service
public class OrderApplicationService {
    private final OrderRepository orderRepository;
    private final InventoryService inventoryService;

    public OrderApplicationService(OrderRepository orderRepository, InventoryService inventoryService) {
        this.orderRepository = orderRepository;
        this.inventoryService = inventoryService;
    }

    // 创建订单
    public Long createOrder(String customerId, List<OrderItemDto> itemDtos) {
        // 转换 DTO 为领域模型
        List<OrderItem> items = itemDtos.stream()
                .map(dto -> new OrderItem(dto.getProductId(), dto.getQuantity(), dto.getPrice()))
                .toList();

        // 检查库存
        items.forEach(item -> inventoryService.reserveStock(item.getProductId(), item.getQuantity()));

        // 创建订单
        Order order = new Order(customerId, items);
        orderRepository.save(order);
        return order.getId();
    }

    // 更新订单状态
    public void updateOrderStatus(Long orderId, OrderStatus status) {
        Order order = orderRepository.findById(orderId).orElseThrow(() -> new RuntimeException("订单不存在"));
        order.updateStatus(status);
        orderRepository.save(order);
    }

    // 查询订单
    public OrderDto getOrderById(Long orderId) {
        Order order = orderRepository.findById(orderId).orElseThrow(() -> new RuntimeException("订单不存在"));
        return OrderDto.fromDomain(order);
    }
}

3.3 基础设施层设计

仓储实现

@Repository
public class JpaOrderRepository implements OrderRepository {
    private final SpringDataOrderJpaRepository jpaRepository;

    public JpaOrderRepository(SpringDataOrderJpaRepository jpaRepository) {
        this.jpaRepository = jpaRepository;
    }

    @Override
    public void save(Order order) {
        jpaRepository.save(order);
    }

    @Override
    public Optional<Order> findById(Long id) {
        return jpaRepository.findById(id);
    }
}

事件机制

@Component
public class DomainEventPublisher {
    private final ApplicationEventPublisher eventPublisher;

    public DomainEventPublisher(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }

    public void publish(Object event) {
        eventPublisher.publishEvent(event);
    }
}

3.4 接口层设计

订单控制器

@RestController
@RequestMapping("/api/orders")
public class OrderController {
    private final OrderApplicationService orderService;

    public OrderController(OrderApplicationService orderService) {
        this.orderService = orderService;
    }

    @PostMapping
    public ResponseEntity<Long> createOrder(@RequestBody OrderRequest request) {
        Long orderId = orderService.createOrder(request.getCustomerId(), request.getItems());
        return ResponseEntity.status(HttpStatus.CREATED).body(orderId);
    }

    @PutMapping("/{orderId}/status")
    public ResponseEntity<Void> updateStatus(@PathVariable Long orderId, @RequestParam OrderStatus status) {
        orderService.updateOrderStatus(orderId, status);
        return ResponseEntity.ok().build();
    }

    @GetMapping("/{orderId}")
    public ResponseEntity<OrderDto> getOrderById(@PathVariable Long orderId) {
        return ResponseEntity.ok(orderService.getOrderById(orderId));
    }
}

3.5 示例数据传输对象(DTO)

public class OrderDto {
    private Long id;
    private String customerId;
    private List<OrderItemDto> items;
    private OrderStatus status;

    public static OrderDto fromDomain(Order order) {
        return new OrderDto(order.getId(), order.getCustomerId(),
                order.getItems().stream().map(OrderItemDto::fromDomain).toList(),
                order.getStatus());
    }
}

4. 运行与测试

数据库表结构(MySQL 示例)

CREATE TABLE orders (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    customer_id VARCHAR(255),
    status VARCHAR(50)
);

CREATE TABLE order_items (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    order_id BIGINT,
    product_id BIGINT,
    quantity INT,
    price DECIMAL(10,2),
    FOREIGN KEY (order_id) REFERENCES orders(id)
);

测试示例

  1. 创建订单

    POST /api/orders
    {
        "customerId": "123",
        "items": [
            { "productId": 1, "quantity": 2, "price": 50.00 },
            { "productId": 2, "quantity": 1, "price": 100.00 }
        ]
    }
    
  2. 更新订单状态

    PUT /api/orders/1/status?status=PAID
    
  3. 查询订单

    GET /api/orders/1
    

这套设计是 DDD 的小型实践示例,后续可以扩展领域事件、复杂聚合和限界上下文的实现。

【React】 领域驱动设计之路(一):理论篇 在 React 应用中采用领域驱动设计是为了更好地应对复杂业务场景和提高代码的可维护性。领域驱动设计并非一蹴而就的实践,而是一个深度理论的集合。在本文中,我将分享我学习 DDD 的过程,以及我们团队在项目中如何应用这一理论,以便大家快速了解其核心概念和实践方法。 阅读详情

相关推荐

深入探索领域驱动设计(DDD):从概念到实践,架构之道

同时,六边形架构提供了一种有效的架构模式,帮助我们隔离业务逻辑和外部依赖,提高系统的灵活性和可测试性。领域驱动设计(Domain-Driven Design,简称DDD)是一种软件开发方法论,旨在通过深入理解业务领域并将其反映到软件设计中,构建高度可维护、可扩展的复杂应用程序。通过DDD的方法和六边形架构,我们能够更好地理解和建模复杂的业务领域,提高软件架构的可维护性和可扩展性。在六边形架构中,外部系统与应用服务层之间通过接口进行通信,应用服务层将请求转发给领域层处理,领域层包含领域模型和业务规则的实现。

UoEmacs_Lisp的博客 246

实战来了,如何基于DDD实现订单创建?

*** 库存预扣减* @param lockRequest 扣减对象*//*** 获取库存数据*/...这里需要说明的是,由于我们系统中通过自定义OpenFeign的解码器来实现包装对象的自动解码(参见优雅远程调用,微服务中ACL与OpenFeign的绝佳配合),这要求接口必须要有返回值,如果是void的则不会经过解码器处理,无法正确解析业务异常。

竹林幽深 1566

你需要这样一个Ros软路由—— 路由器+外网+一号通ip线路=动态ip的WiFi信号

功能强大 管理便捷—给您全新的路由体验 一键更换指定线路or批量更换所有IP/MAC/SSID 自定义走本地网络策略的分流功能 设备批发价、不限制拨号账号服务商 强大的单设备/多设备IP去重功能 批量导入、管理一号通线路 一键任意切换5G_WiFi(推荐)/2.4G_WiFi(建议不用) 设备支持PPTP/L2TP/SSTP/openVP.N等协议 独家支持openVPN,适用于网络受限用户 支持自行接入AP和交换机扩容 一键打开/关闭所有虚拟WiFi 一键隐藏/显示设备WiFi...

米粒儿 4258

DDD领域驱动设计内容分享(十五):从携程订单系统重构,看DDD的巨大价值

携程用车订单业务包括接送机、包车、打车等产线,涉及订单状态管理、支付状态管理、供应商订单状态管理、履约状态管理等功能。履约状态关乎司机相关状态,完成订单需结清额外费用。携程租车订单业务涵盖订单状态管理、支付状态管理、押金扣除记录、供应商订单状态管理、履约状态管理等功能。履约状态主要涉及取还车相关状态。通过划分上下文和明确职责,各个领域负责自己的数据和领域知识。这样一来,订单不再涉及这些字段,而是由数据写入的业务方负责维护。因此,在后续与订单无关的业务逻辑发生变化时,订单无需进行修改。

之乎者也·的博客 1136

虚拟机器人平台CoppeliaSim(Vrep)的逆运动学教学

相信看这篇博客的人都知道CoppeliaSim是做什么的,因此这里不多赘述。CoppeliaSim从最早的Vrep到现在已经更新了N个版本,从过去Vrep3.x开始使用的我这里小小地吐槽一下这个软件。CoppeliaSim每一个版本都有更新,问题是这些更新有时候不能向前兼容,而且时不时更新地让人不知所措(对于有紧急任务的时候真的很火大啊)。 以本文所展示地逆运动学来说,CoppeliaSim在4.0.0之后又大变,推翻了过往所有的拖动模块链接之类的构建方式,转而采用直接通过代码来实现逆运动学。 简单版逆运动

qq_39243015的博客 6699

干货 | 降低复杂度提升效率,DDD在携程用车/租车订单系统重构中的实践

作者简介小白龙,携程资深后端开发工程师,关注架构落地、研发效能领域。随着历史业务不断迭代和业务场景越来越复杂,携程用车、租车(简称两车)面临历史技术债和系统复杂度越来越高带来的理解、维护、迭代困难等问题,我们开始寻求如何更有效的降低复杂度和提升效率的方法。本文描述了两车如何利用DDD(Domain-driven Design,领域驱动设计)方法论降低系统复杂度以及在重构历史系统中的取舍和思考。对于...

携程技术 2850

武汉理工大学数据结构综合实验——连连看游戏综合实践

文章目录实验目的主要仪器设备及耗材一、实验要求二、分析与设计(非线性结构)1.数据结构的设计2.核心算法设计一条直线消子两条直线消子三条直线消子初始化游戏地图搜寻路径提示和重排3.测试用例设计4.测试效果总结 实验目的 (1)线性结构实验目的 调研连连看游戏,了解连连看游戏的功能和规则等 掌握集成开发工具VS2019的使用和C++的基础编程 了解MFC框架 了解线性结构,掌握数组的遍历、消子和胜负判断等算法 了解企业软件开发过程,应用迭代开发思路进行项目开发,养成良好的编程习惯和培养软件工程化思维 .

mo_zhe的博客 7612

业务单据进行领域驱动设计的最佳实践

本文以电商购物场景为例,介绍了领域驱动设计的应用实践。你会发现,DDD的核心目标就是通过各种实用性的方法和技巧提炼出具有体现问题实质的领域模型,协作解决领域问题,从而掌控问题领域本身的错综复杂性。DDD之于爱它的人,就像一个复杂、有挑战性的玩具,在思考问题本质、抽象知识模型中,进入心流状态。

阿里技术 4689

攻防世界 web高手进阶区 9分题 Web_python_flask_sql_injection

继续ctf的旅程,开始攻防世界web高手进阶区的9分题,本文是Web_python_flask_sql_injection的writeup

闵行小鱼塘 1473

新手避坑指南:手把手教你从零编写DC综合的.synopsys_dc.setup配置文件

本文详细介绍了如何从零开始编写DC综合的.synopsys_dc.setup配置文件,帮助新手避开常见误区。内容涵盖工艺库路径设置、核心参数详解、实用调试技巧以及高效配置模板,特别强调了配置文件在数字IC设计流程中的重要性。通过实战案例和常见报错解决方案,读者可以快速掌握DC综合配置的关键技能。

weixin_30517215的博客 296

领域驱动设计DDD实战进阶第一波(十):订单上下文领域逻辑、订单上下文应用服务用例与接口...

DDD实战进阶第一波(十):开发一般业务的大健康行业直销系统(订单上下文领域逻辑) 前一篇文章主要讲了订单上下文的POCO模型,其中订单与订单项中有大量的值对象。这篇文章主要讲讲这些值对象以及订单项、订单相关的领域逻辑。 1.ProductSKUs值对象领域逻辑: ProductSKUs...

chuhe0321的专栏 1314

高通410刷OpenWRT后网络共享配置全攻略

本文详细解析了在高通410设备刷入OpenWRT后,因基带文件丢失导致无法上网的常见问题。核心解决方案是通过SMB网络共享,将备份的原厂基带文件传输至OpenWRT系统并正确还原,从而恢复移动网络连接。文章提供了从备份基带、刷机到配置共享和文件替换的完整操作指南。

grafana6viz的博客 572

领域驱动设计(DDD)是什么?——从理论到实践的全方位解析

领域驱动设计(DDD)概述DDD 是一种以业务领域为核心的建模方法,它主张从实际业务问题中提炼出领域模型,并借助与业务专家共同构建的“普适语言”,确保开发人员与业务人员在同一概念体系下沟通与协作。核心目标捕捉复杂业务逻辑:将实际业务中的规则和流程精确地映射到代码模型中。降低系统耦合:通过划分业务边界,使得各模块之间保持高度独立,从而提升代码复用性和系统灵活性。高内聚、低耦合的系统构建高内聚:指系统内部各模块、组件围绕单一业务目标组织,职责单一,内部关系紧密。

开源AI 专属 UI——papyrai-ui。《千界明彻录》(故事形式构建元思维)——胡说小说。更多思辨内容在公众号。 2486

新手必看:C#调用YOLO模型完成图片/视频目标检测(上位机版)

新手学习C#调用YOLO模型,核心是先把基础流程跑通,再逐步优化。图片检测是基础,视频检测就是在图片的基础上加循环和线程,而上位机的实际项目,就是在这个基础上适配工业硬件和业务需求。本文的代码都是新手能直接复制运行的,如果你运行时遇到问题,先检查前期准备是否到位,再看避坑指南。记住,新手别追求一步到位,先实现功能,再慢慢优化性能和界面。等你能熟练调用YOLO模型后,再去研究模型训练、量化优化等进阶内容,会轻松很多。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 988

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

DDD领域驱动设计C++实现案例:订单管理系统

领域驱动设计(Domain-Driven Design)是一种软件开发方法论,强调将业务领域的概念和规则融入软件设计中。值对象(Value Object): 无唯一标识,基于属性值判断相等性实体(Entity): 有唯一标识,其生命周期由聚合根管理聚合根(Aggregate Root): 聚合的根节点,维护聚合内的一致性领域服务(Domain Service): 处理跨实体的业务逻辑仓储(Repository): 提供数据持久化接口// 地址值对象 - 无唯一标识,基于属性值相等。

码事漫谈 1268

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

领域驱动设计 (DDD):深入理解与实践

领域驱动设计(DDD)是由Eric Evans在其同名书籍《领域驱动设计:软件核心复杂性应对之道》中提出的一种方法论。DDD强调通过建立清晰的领域模型来解决复杂业务问题,将业务专家和开发团队紧密合作,并利用模型与代码之间的紧密联系来有效地解决业务复杂性。核心思想:在DDD中,"领域"指的是业务活动的核心,而"驱动设计"则是指通过领域知识驱动软件设计,确保软件的架构和设计能准确反映业务逻辑,帮助开发团队在技术和业务之间架起一座桥梁。

Doug Wang的博客 1538

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

[DDD] 领域驱动设计简介

领域驱动设计简介

YZJincsdn的博客 1060

领域驱动设计(DDD)与 Spring Boot 3 简介

DDD 是一种以业务为核心的开发方法,通过实体、聚合、仓储等概念组织代码,适合复杂业务系统。Spring Boot 3 的模块化设计和丰富生态使其成为实现 DDD 的理想框架。通过合理分层和设计,可以构建出高内聚、低耦合的系统,提升代码质量和业务响应能力。

qq_65798460的博客 1056

领域驱动设计(DDD)实践指南

📕我是廖志伟,一名Java开发工程师、《Java项目实战——深入理解大型互联网企业通用技术》(基础篇)、(进阶篇)、(架构篇)清华大学出版社签约作家、Java领域优质创作者、优快云博客专家、阿里云专家博主、51CTO专家博主、产品软文专业写手、技术文章评审老师、技术类问卷调查设计师、幕后大佬社区创始人、开源项目贡献者。

我是Java程序员廖志伟,感谢朋友们的支持!不定期贡献一篇高品质、过万文字、图文并茂且附有视频解说、满载代码示例注释的良心之作,坚决杜绝粗制乱造。 842

领域驱动设计:实践指南

1.背景介绍 领域驱动设计(Domain-Driven Design,DDD)是一种软件设计方法,它强调将业务领域的知识与软件系统紧密结合,以实现更高效、可靠、易于维护的软件系统。DDD 起源于2003年,由俄罗斯软件工程师艾伦·赫尔曼(Eric Evans)在其书籍《领域驱动设计:实践指南》中提出。 DDD 的核心思想是将软件系统的设计和实现与业务领域紧密结合,以便更好地理解和满足业务需求。...

AI天才研究院 459

DDD学习笔记

DDD 分层架构通过清晰的职责划分,确保系统的可维护性和可扩展性。用户界面层专注于用户交互,应用层管理业务流程,领域层负责核心业务逻辑,而基础设施层提供技术支持。这种架构有助于团队在开发过程中明确各部分的职责,从而提高开发效率和系统的稳定性。方法:与业务方紧密合作,明确系统中的核心业务逻辑和支撑逻辑,将资源集中在核心领域。

dhrmt的博客 938

领域驱动设计实践中的核心要点与落地思考

典型的贫血模型将数据和行为分离,导致业务逻辑散落在各个Service中。领域驱动设计(DDD)包含战术设计和战略设计两个维度,两者相辅相成。正确做法是保持领域模型的独立性,通过仓储模式实现与持久化层的解耦。建议根据业务一致性边界划分聚合,并通过聚合根控制内部对象的访问。但需注意保持领域服务的无状态性,避免演变成传统Service的"大杂烩"。实际使用中发现,平台的一键部署功能特别适合展示领域模型的实际运行效果,无需繁琐的环境配置,让开发者可以专注于领域设计本身。,可以快速体验领域驱动设计的实践过程。

DiamondWolf89的博客 403

DDD培训课程与视频资源全攻略

DDD培训课程与视频资源全攻略 本文全面分析了领域驱动设计(DDD)的培训课程、在线学习平台、视频讲座和会议演讲等学习资源,并提供了系统化的自学路径规划。内容包括知名培训机构和讲师(如Eric Evans、Vaughn Vernon等)的课程特色分析,主流在线平台(Pluralsight、Udemy等)的课程对比,以及精选的视频资源和会议演讲汇总,旨在为开发者提供一份完整的DDD学习指南。 知名培...

gitblog_00515的博客 980

AI DDD重构实践

2025 年初,我们决定启动架构重构,**从传统的 MVC 架构迁移到 DDD(领域驱动设计)四层架构**。| **Domain** | 核心业务逻辑 | Entities, Value Objects, Domain Services | HTTP 处理、数据库访问 || **第四阶段** | Steps 41-52 | Repository 模式引入 | 创建 Repository 层 |│ │ (HTTP API) │ │ (路由定义) │ │ (认证/日志) │ │。

mtngt11的博客 684
上一篇: 领域驱动设计(DDD)适合 DDD 的项目案例 三
下一篇: Alibaba Spring Cloud 一 核心组件、特性
十方来财
十方来财 新星创作者: 编程框架技术领域 新星创作者: 编程框架技术领域
博客等级 码龄14年 8360粉丝 346原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十方来财

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值