Android应用DDD实践:聚合根与应用服务的通信方式探讨
关于Android项目中DDD实现用户姓名修改的问题解答
你当前的实现不建议在领域实体(User)中直接注入应用服务(AccountService),这违反了DDD中领域层与应用层的职责边界——领域实体应专注于表达业务规则、维护自身状态,而与外部系统(如后端)的交互属于应用服务的职责范围。
以下是两种更优的实现方式:
方式一:将外部交互职责转移到应用服务
应用服务作为协调者,负责串联领域实体的业务逻辑与外部后端的同步操作,领域实体只处理自身状态变更和业务规则。
// 领域实体User:仅关注业务规则与状态维护 class User(var name: String) { fun changeName(newName: String) { // 这里可添加姓名格式校验等业务规则,比如长度限制、非法字符检查 name = newName // 触发领域事件,用于后续可能的业务联动 fireEvent(UserNameChanged(name)) } } // 应用服务:协调领域逻辑与外部交互 class AccountAppService( private val accountService: AccountService, private val userRepository: UserRepository ) { fun updateUserName(userId: String, newName: String) { val user = userRepository.findById(userId) // 先调用后端接口完成同步 val syncSuccess = accountService.changeName(newName) if (syncSuccess) { // 同步成功后,修改领域实体状态 user.changeName(newName) userRepository.save(user) } else { // 处理同步失败逻辑,比如抛出异常、记录告警日志 throw SyncFailedException("同步用户姓名到后端失败") } } }
方式二:基于领域事件的异步同步
如果业务允许本地状态变更与后端同步存在短暂延迟,可通过领域事件解耦两者,提升系统响应速度。
// 领域实体User class User(var name: String) { fun changeName(newName: String) { // 业务规则校验 name = newName // 触发领域事件 fireEvent(UserNameChanged(name)) } } // 领域事件监听器(属于应用层/基础设施层) class UserNameChangedListener(private val accountService: AccountService) { @EventListener fun handleUserNameChanged(event: UserNameChanged) { // 异步调用后端接口完成同步 accountService.changeNameAsync(event.newName) .exceptionally { e -> // 同步失败处理:重试、记录错误日志、触发告警 log.error("同步用户姓名失败:${event.newName}", e) null } } } // 应用服务 class AccountAppService(private val userRepository: UserRepository) { fun updateUserName(userId: String, newName: String) { val user = userRepository.findById(userId) user.changeName(newName) userRepository.save(user) // 事件发布后由监听器自动处理后端同步 } }
核心原则总结
领域实体需保持"纯净",不依赖任何外部服务或基础设施,将外部交互、流程协调的职责交给应用层或基础设施层,这样既符合DDD的分层设计思想,也能让代码更易于测试、维护和扩展。
内容的提问来源于stack exchange,提问作者rayworks
相关产品推荐
相关产品推荐

