客户端应用中DDD实体方法的设计与API调用方式咨询
客户端实体类方法设计与API调用实践
核心原则:实体类专注数据与本地逻辑,远程交互分离到服务类
客户端的Post实体类应该只负责承载帖子数据和处理本地轻量业务逻辑(比如格式化发布时间、判断是否已过期等),远程API调用属于IO操作,耦合性高,不应该放在实体类中。
1. Post.edit()的正确实现方式
实体类里的edit()仅处理本地属性更新,远程提交逻辑交给专门的服务类:
// Post 实体类(Kotlin示例) data class Post( val postId: String, var title: String, var content: String, val createdAt: Long ) { // 仅处理本地属性修改的edit方法 fun edit(newTitle: String, newContent: String) { this.title = newTitle this.content = newContent // 可添加本地基础校验,复杂校验交给服务端 require(newTitle.isNotBlank()) { "标题不能为空" } } }
2. API调用的位置:独立的服务类(PostService)
创建PostService专门负责与服务端API交互,封装HTTP请求细节:
// PostService 服务类 class PostService(private val httpClient: HttpClient) { // 负责调用服务端编辑帖子的API suspend fun submitEdit(postId: String, updatedTitle: String, updatedContent: String): Boolean { return try { val response = httpClient.post("/post/$postId") { body = mapOf( "title" to updatedTitle, "content" to updatedContent ) } response.isSuccessful } catch (e: Exception) { // 处理网络异常、请求失败等场景 false } } }
在客户端业务逻辑层(比如ViewModel)中协调实体和服务:
// 业务逻辑层(ViewModel示例) class PostViewModel(private val postService: PostService) : ViewModel() { fun editPost(localPost: Post, newTitle: String, newContent: String) { // 1. 先更新本地实体 localPost.edit(newTitle, newContent) // 2. 调用服务提交到服务端 viewModelScope.launch { val success = postService.submitEdit(localPost.postId, newTitle, newContent) if (!success) { // 提交失败,回滚本地实体属性 // 比如恢复之前的title和content值 } } } }
3. 是否向Post实体注入PostService?绝对不要
实体类应该保持无状态、无依赖,注入服务会导致:
- 实体类职责混乱,从数据载体变成了业务/IO操作类
- 测试成本升高:测试实体时需要mock服务依赖
- 内存泄漏风险:移动端环境下,实体可能被长期持有,导致服务类无法被回收
4. PostService属于领域服务吗?不属于
在你的场景中,服务端已经承载了所有核心验证和业务逻辑,客户端的PostService只是远程API的代理层(或数据访问层DAL),它的作用仅仅是封装HTTP请求、传递数据,不处理领域核心逻辑。
真正的领域服务是处理领域内复杂业务规则的组件,而客户端仅需承担数据展示和用户交互,不需要承载领域逻辑。
内容的提问来源于stack exchange,提问作者Byte Byte
相关产品推荐
相关产品推荐

