沉默是金,总会发光
大家好,我是沉默
上一篇文章:新来的架构师,把DDD落地得优雅又高级!,有粉丝留言:

所以,今天,将继续深入浅出DDD的核心概念,掌握其关键组件,并学会如何在实际项目中应用。
**-**01-
为什么会有 DDD
你是否经历过这样的困境?系统初期采用MVC架构开发迅速,但随着业务复杂度增加,代码逐渐变得难以维护,各种业务逻辑像意大利面条一样纠缠不清。每次修改都如履薄冰,生怕牵一发而动全身。这背后隐藏着一个关键问题:传统的分层架构无法有效应对复杂业务场景。
今天,我们就从这些问题出发,带你走进 DDD(领域驱动设计)的世界,探索一种让系统"长久健康"的架构之道。
**-**02-
什么是 DDD?
DDD,全称 Domain-Driven Design(领域驱动设计),是一种指导软件工程设计的方法论。它的核心思想是:用业务的视角去切割和组织系统,把复杂的业务逻辑沉淀到"领域模型"中,从而让系统更易维护、可持续演进。
DDD 的分层思想就显得尤为重要------它通过合理的架构分层,降低系统维护和迭代的成本。
**-**03-
DDD的核心构件
- 充血模型 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() { /* 取消逻辑 */ }
}
- 领域模型
领域模型是对业务核心的建模,既包含数据,也包含行为。它不是简单的数据结构,而是业务规则的载体。DDD 推荐用充血模型实现领域模型。
- 实体(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;
// 构造后不可修改
}
- 聚合与聚合根
聚合是将紧密相关的实体和值对象组织在一起的业务模块。聚合根是聚合的唯一入口,外部只能通过聚合根访问聚合内部对象。
typescript
public class Order { // 聚合根
private Long orderId;
private List<OrderItem> items;
private Address address;
public void addItem(OrderItem item) { ... }
public void changeAddress(Address address) { ... }
}
- 仓储(Repository)
仓储是领域模型与持久化技术的桥梁。它用业务视角提供查找、保存领域对象的接口,屏蔽底层数据库、缓存等实现细节。
csharp
public interface OrderRepository {
Order findById(Long id);
void save(Order order);
void delete(Long id);
}
- 适配器(Adapter)
适配器负责与外部系统对接,如短信、支付等。领域层只定义接口,具体实现由基础设施层完成,便于切换和扩展。
typescript
public interface SmsSender {
void sendCode(String mobile, String code);
}
public class AliyunSmsSender implements SmsSender { ... }
public class TencentSmsSender implements SmsSender { ... }
- 领域编排(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);
}
}
- 触发器层(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(《领域驱动设计》作者)
热门文章
**-**05-
粉丝福利
点点关注,送你 Spring Cloud 微服务实战,如果你正在做项目,又或者刚准备做。可以仔细阅读一下,或许对你有所帮助!