让我们一起用 DDD,构建更美好的软件世界!

沉默是金,总会发光

大家好,我是沉默

上一篇文章:新来的架构师,把DDD落地得优雅又高级!,有粉丝留言:

所以,今天,将继续深入浅出DDD的核心概念,掌握其关键组件,并学会如何在实际项目中应用。

**-**01-

为什么会有 DDD

你是否经历过这样的困境?系统初期采用MVC架构开发迅速,但随着业务复杂度增加,代码逐渐变得难以维护,各种业务逻辑像意大利面条一样纠缠不清。每次修改都如履薄冰,生怕牵一发而动全身。这背后隐藏着一个关键问题:传统的分层架构无法有效应对复杂业务场景

今天,我们就从这些问题出发,带你走进 DDD(领域驱动设计)的世界,探索一种让系统"长久健康"的架构之道。

**-**02-

什么是 DDD?

DDD,全称 Domain-Driven Design(领域驱动设计),是一种指导软件工程设计的方法论。它的核心思想是:用业务的视角去切割和组织系统,把复杂的业务逻辑沉淀到"领域模型"中,从而让系统更易维护、可持续演进。

DDD 的分层思想就显得尤为重要------它通过合理的架构分层,降低系统维护和迭代的成本。

**-**03-

DDD的核心构件

  1. 充血模型 vs 贫血模型

贫血模型:只有数据属性,没有业务逻辑,所有行为都在 Service 层。

充血模型:属性和行为都聚合在一个类中,业务逻辑与数据紧密结合。

kotlin 复制代码
// 贫血模型
public class Order {
    private Long id;
    private Long userId;
    private BigDecimal amount;
    // 没有任何行为
}
// 充血模型
public class Order {
    private Long id;
    private Long userId;
    private BigDecimal amount;
    public void pay(Payment payment) { /* 支付逻辑 */ }
    public void cancel() { /* 取消逻辑 */ }
}
  1. 领域模型

领域模型是对业务核心的建模,既包含数据,也包含行为。它不是简单的数据结构,而是业务规则的载体。DDD 推荐用充血模型实现领域模型。

  1. 实体(Entity)与值对象(Value Object)

实体:有唯一标识(如 id),即使属性变化,身份不变。例如订单、用户。

值对象:无唯一标识,属性完全相同即为同一个对象,且不可变。例如地址。

arduino 复制代码
// 实体
public class User {
    private Long id;
    private String name;
    private int age;
}
// 值对象
public class Address {
    private final String province;
    private final String city;
    private final String street;
    // 构造后不可修改
}
  1. 聚合与聚合根

聚合是将紧密相关的实体和值对象组织在一起的业务模块。聚合根是聚合的唯一入口,外部只能通过聚合根访问聚合内部对象。

typescript 复制代码
public class Order {  // 聚合根
    private Long orderId;
    private List<OrderItem> items;
    private Address address;
    public void addItem(OrderItem item) { ... }
    public void changeAddress(Address address) { ... }
}
  1. 仓储(Repository)

仓储是领域模型与持久化技术的桥梁。它用业务视角提供查找、保存领域对象的接口,屏蔽底层数据库、缓存等实现细节。

csharp 复制代码
public interface OrderRepository {
    Order findById(Long id);
    void save(Order order);
    void delete(Long id);
}
  1. 适配器(Adapter)

适配器负责与外部系统对接,如短信、支付等。领域层只定义接口,具体实现由基础设施层完成,便于切换和扩展。

typescript 复制代码
public interface SmsSender {
    void sendCode(String mobile, String code);
}
public class AliyunSmsSender implements SmsSender { ... }
public class TencentSmsSender implements SmsSender { ... }
  1. 领域编排(Application Layer)

应用层负责组装和编排多个领域服务,实现完整的业务流程。例如"用户开户成功,自动赠送优惠券并发送短信通知":

arduino 复制代码
public class OpenAccountOrchestrationService {
    private final UserService userService;
    private final MarketingService marketingService;
    private final NotifyService notifyService;
    public void openAccountAndGiftCoupon(String userId) {
        userService.openAccount(userId);
        marketingService.giftCoupon(userId);
        notifyService.sendAccountOpenMessage(userId);
    }
}
  1. 触发器层(Trigger Layer)

触发器层负责接收外部输入(如 HTTP、MQ、定时任务等),触发业务流程,但不包含业务逻辑。

less 复制代码
@RestController
@RequestMapping("/user")
public class UserController {
    private final UserOrchestrationService userOrchestrationService;
    @PostMapping("/register")
    public ResultVO register(@RequestBody RegisterRequest req) {
        userOrchestrationService.registerAndGiftCoupon(req.getMobile());
        return ResultVO.success();
    }
}

**-**04-

典型的DDD项目结构

bash 复制代码
src/
├── domain/                         # 领域层(核心业务)
│   ├── user/                       # 用户子域
│   │   ├── User.java               # 实体
│   │   ├── UserRepository.java     # 仓储接口
│   │   ├── UserService.java        # 领域服务
├── application/                    # 应用层(业务流程编排)
│   ├── OpenAccountOrchestrator.java 
├── trigger/                        # 触发层(外部入口)
│   ├── OpenAccountController.java   # HTTP接口
│   ├── OpenAccountListener.java     # MQ监听
├── infrastructure/                 # 基础设施层
│   ├── repository/                 # 仓储实现
│   ├── adapter/                    # 外部适配器

结语:大道至简,领域为王

架构的终极目标,是让系统能够优雅地应对变化。DDD 让我们回归业务本质,用领域驱动设计,打造可持续演进的系统。正如那句金句所说:

"唯有理解业务,方能驾驭技术。"

"复杂性不在于技术本身,而在于我们对业务的理解程度。DDD不是技术解决方案,而是认知工具,它帮助我们更清晰地思考业务问题。" ------ Eric Evans(《领域驱动设计》作者)


热门文章

一套能保命的高并发实战指南

架构师必备:用 AI 快速生成架构图

**-**05-

粉丝福利

点点关注,送你 Spring Cloud 微服务实战,如果你正在做项目,又或者刚准备做。可以仔细阅读一下,或许对你有所帮助!

相关推荐
亿道电子Emdoor30 分钟前
【ARM】ARM架构的发展和相关架构
arm开发·架构·arm
二哈喇子!2 小时前
若依【(前后端分离版)SpringBoot+Vue3】
java·spring boot·后端
paopaokaka_luck3 小时前
婚纱摄影管理系统(发送邮箱、腾讯地图API、物流API、webSocket实时聊天、协同过滤算法、Echarts图形化分析)
vue.js·spring boot·后端·websocket·算法·echarts
Monkey-旭5 小时前
Android Handler 完全指南
android·java·handler
秃狼6 小时前
Execel文档批量替换标签实现方案
java
Brookty6 小时前
Java线程安全与中断机制详解
java·开发语言·后端·学习·java-ee
Sylvia-girl6 小时前
排序查找算法,Map集合,集合的嵌套,Collections工具类
java·算法·排序算法
TT哇6 小时前
【分治】归并排序——排序数组(medium)
java·算法·排序算法
给力学长6 小时前
自习室预约小程序的设计与实现
java·数据库·vue.js·elementui·小程序·uni-app·node.js
试着6 小时前
零基础学习性能测试第五章:JVM性能分析与调优-JVM概念,java程序运行原理
java·jvm·学习·零基础·性能测试