You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android MVVM应用Domain层UseCase架构设计及Clean合规性疑问

直接在Domain层实现UseCase是否违反Clean架构?

首先明确结论:直接在Domain层实现UseCase完全符合Clean架构的核心规则,反而某些示例中拆分UseCase接口到Domain、实现到Data的做法,是对Clean架构的误解。

先理清Clean架构中各层的核心职责

Clean架构的核心是依赖规则:内层(Domain)不依赖外层(Data、Presentation),外层依赖内层的抽象。各层的核心分工是:

  • Domain层:最内层,包含业务实体(Entities)和业务用例(Use Cases)——这部分是业务规则的核心,是整个应用最稳定的部分。Use Cases的本质是业务逻辑的执行流程封装,它定义了“为了完成某个业务目标,需要调用哪些业务规则、依赖哪些外部端口(比如Repository抽象)”。
  • Interface Adapters层(对应你的Data层):负责将Domain层的抽象端口(比如Repository接口)适配到具体的外部实现(比如Room数据库、Retrofit接口),它依赖Domain层的抽象,而不是反过来。

为什么说“Domain层UseCase无需抽象”?

你提到的“为UseCase加抽象是过度设计”的判断,在绝大多数常规业务场景下是正确的,原因有两点:

  1. UseCase的业务逻辑是Domain层的核心:UseCase本身就是业务规则的具体执行载体,它的变化只来自业务需求的变更,而不是外部依赖的替换。外部依赖的替换(比如从网络数据源换成本地数据源),是通过依赖Domain层的Repository抽象来实现的——你只需要替换Data层的RepositoryImpl,UseCase的代码完全不需要改动。
  2. 抽象UseCase的适用场景极少:只有当同一个业务流程存在完全不同的业务逻辑实现时,才需要为UseCase定义抽象。比如“登录UseCase”有“密码登录”“验证码登录”两种完全不同的业务规则,这时候可以在Domain层定义LoginUseCase接口,然后分别实现PasswordLoginUseCase和OtpLoginUseCase。但这种场景并不常见,大部分业务的UseCase逻辑是单一且稳定的,不需要额外抽象。

澄清对“Domain层仅含抽象”的误解

你提到的“Domain层应仅包含抽象,实现放Interface Adapters层”,是混淆了外部依赖端口和业务逻辑实现的区别:

  • 属于“外部依赖端口”的组件(比如Repository),确实需要在Domain层定义抽象,实现放在Data层——因为Repository是Domain层需要依赖的外部能力,Domain不需要关心具体怎么实现,只需要定义需要什么能力。
  • 但UseCase不属于“外部依赖端口”,它是Domain层自己的业务逻辑执行单元,本身就是Domain层的核心实现,自然应该放在Domain层。

推荐的包结构实践

结合你的Android MVVM场景,推荐的核心包结构应该是:

├── domain/
│   ├── entities/          # 业务实体(比如User、Order)
│   ├── repositories/      # Repository接口(比如UserRepository)
│   └── usecases/          # UseCase实现类(比如GetUserUseCase、UpdateUserUseCase)
│       ├── GetUserUseCase.kt
│       └── UpdateUserUseCase.kt
├── data/
│   ├── repositories/      # Repository实现类(比如UserRepositoryImpl)
│   ├── datasources/       # 具体数据源(比如UserLocalDataSource、UserRemoteDataSource)
│   └── models/            # 数据层模型(比如UserDto,用于和数据源交互)
└── presentation/
    ├── viewmodels/        # ViewModel,依赖Domain层的UseCase
    └── activities/        # Activity/Fragment

在这个结构中:

  • GetUserUseCase直接在Domain层实现,依赖UserRepository接口
  • UserRepositoryImpl在Data层实现,依赖具体的数据源
  • ViewModel通过DI注入GetUserUseCase,完全不依赖Data层,符合依赖规则

内容的提问来源于stack exchange,提问作者Kratos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 01:12:06