在传统的 DDD 设计中,我们往往会想下面这样写
// 数据结构 (通常是一个简单的 POJO/POCO)
class User {
private Long id;
private String name;
private String email;
// 只有 getters 和 setters...
}
// 操作数据的过程/服务
class UserService {
private UserRepository userRepository;
// 过程一:创建用户
public void createUser(UserDTO userData) {
User user = new User();
user.setName(userData.getName());
user.setEmail(userData.getEmail());
// ... 其他业务逻辑和校验
userRepository.save(user);
}
// 过程二:更新用户
public void updateUser(Long userId, UserDTO userData) {
User user = userRepository.findById(userId);
user.setName(userData.getName());
// ... 其他业务逻辑和校验
userRepository.save(user);
}
}
在这个结构中:
User
实体(Entity)是“贫血”的:它几乎没有任何业务逻辑,只是一个数据的容器。它的所有属性都可以通过set
方法被外界随意修改,自身不负责维护其数据的一致性和业务规则。它就像一个 C 语言中的struct
。UserService
是一个“过程脚本”:所有的业务逻辑、验证规则、状态变更都集中在UserService
中。UserService
就像一个包含了一系列函数的模块,它接收数据(User
对象),处理它,然后输出结果。这个服务“指挥”着User
对象,而不是User
对象“自己行动”。
当业务逻辑变得复杂时,不同的事务脚本之间很容易出现代码重复。由于没有一个核心的、富含业务逻辑的领域模型,业务规则会散落在系统的各个角落,难以维护和演进。最典型的就是 Smart UI。
在真正的DDD中,我们追求的是充血模型(Rich Domain Model)。
- 完全面向对象(没有 service)
- 所有模型建立成完全连接的对象图(所有聚合都不会断开)
- 所有模型会直接映射成 RESTful api(HATEOAS 形式)
- 屏蔽所有实现细节抽象层
- 概念模型、模型、api 上完全映射一致 代码样例