跳到主要内容

Clean Architecture

问题

如何在 Android 中实现 Clean Architecture?

答案

三层架构

职责依赖
PresentationUI 展示、用户交互依赖 Domain
Domain业务逻辑(纯 Kotlin)不依赖任何层
Data数据访问实现依赖 Domain(实现接口)

Domain Layer

// Domain Model(纯数据,无 Android 依赖)
data class User(
val id: String,
val name: String,
val email: String,
val isActive: Boolean
)

// Repository Interface(Domain 只定义接口)
interface UserRepository {
suspend fun getUser(id: String): User
suspend fun getUsers(): List<User>
fun getUsersFlow(): Flow<List<User>>
}

// UseCase(封装单个业务操作)
class GetActiveUsersUseCase(
private val repository: UserRepository
) {
operator fun invoke(): Flow<List<User>> {
return repository.getUsersFlow()
.map { users -> users.filter { it.isActive } }
}
}

Data Layer

// DTO(网络数据传输对象)
@Serializable
data class UserDto(
val id: String,
val name: String,
val email: String,
@SerialName("is_active")
val isActive: Boolean
)

// Mapper(DTO → Domain Model)
fun UserDto.toDomain() = User(
id = id,
name = name,
email = email,
isActive = isActive
)

// Repository 实现
class UserRepositoryImpl(
private val api: ApiService,
private val dao: UserDao
) : UserRepository {

override suspend fun getUser(id: String): User {
return api.getUser(id).toDomain()
}

override fun getUsersFlow(): Flow<List<User>> {
return dao.getAllUsers().map { entities ->
entities.map { it.toDomain() }
}
}
}

Presentation Layer

class UserListViewModel(
private val getActiveUsers: GetActiveUsersUseCase
) : ViewModel() {

val users: StateFlow<List<User>> = getActiveUsers()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
}
Domain Layer 何时使用?

Domain Layer 是可选的。当出现以下情况时应该引入:

  • 多个 ViewModel 共享相同的业务逻辑
  • 业务逻辑复杂需要单独测试
  • 项目需要清晰的模块边界

简单的 CRUD 页面直接在 ViewModel 中调用 Repository 即可。


常见面试问题

Q1: UseCase 只有一行代码也要写吗?

答案

简单的 CRUD 不需要 UseCase,直接在 ViewModel 中调用 Repository。UseCase 适用于:

  • 组合多个 Repository 的数据
  • 包含业务规则(如过滤、验证、计算)
  • 多个 ViewModel 共享同一逻辑

Q2: 为什么 Domain Layer 不能依赖 Android?

答案

Domain Layer 是纯 Kotlin 模块,不依赖 Android 框架,这样:

  1. 可测试性:直接用 JUnit 测试,不需要 Android 环境
  2. 可复用性:可以在 KMP(Kotlin Multiplatform)中共享
  3. 依赖倒置:Domain 定义 Repository 接口,Data 层实现,符合 SOLID 原则

相关链接