遵循Clean Architecture如何获取单例State类数据 能否作为Repository数据源
结论先行
直接将这个EngineViewState单例作为Repository的数据源不符合Clean Architecture规范,原因和正确实现方式如下:
1. 现有用法不合规的原因
你当前定义的EngineViewState属于UI层专属的状态类:
- 它依赖了Compose框架特有的
MutableState类型,不属于数据层/领域层的通用类型 - Clean Architecture要求依赖方向向内,外层(UI层)的实现不能被内层(数据层/领域层)直接依赖,否则会导致内层耦合UI框架,后续替换UI方案、做单元测试都会受到严重影响
- 单例UI状态如果直接被Repository依赖,还会导致状态生命周期和业务逻辑强行绑定,容易出现内存泄漏、跨页面状态污染的隐患
2. 符合规范的实现方案
你可以按照分层职责拆分实现:
第一步:抽离领域层数据模型
在Domain层定义不依赖任何框架的纯Kotlin数据类,作为业务数据的通用载体:
// 领域层纯数据类,无任何外部框架依赖 data class EngineParam( val cylinderQuantity: Float = 0f, val inGapNormal: String = "0.0" )
第二步:定义Domain层Repository接口
定义数据操作的抽象,屏蔽下层实现细节,业务逻辑只依赖这个接口:
interface EngineParamRepository { fun getEngineParam(): EngineParam fun saveEngineParam(param: EngineParam) // 需要观察数据变化可以加Flow版本的接口 fun observeEngineParam(): Flow<EngineParam> }
第三步:在Data层实现Repository
你可以用原来的单例状态作为内存缓存的实现载体,同时做类型转换解耦UI层依赖:
class EngineParamRepositoryImpl: EngineParamRepository { // 内存缓存复用你原来的单例实现 private val cacheState = EngineViewState() // 可选:补充Room/SharedPreferences持久化逻辑 override fun getEngineParam(): EngineParam { return EngineParam( cylinderQuantity = cacheState.getCylinderQuantity().value, inGapNormal = cacheState.getInGapNormal().value ) } override fun saveEngineParam(param: EngineParam) { cacheState.setCylinderQuantity(param.cylinderQuantity) cacheState.setInGapNormal(param.inGapNormal) // 可选:同步写入持久化存储 } override fun observeEngineParam(): Flow<EngineParam> { // 将MutableState转为Flow提供给业务层使用 return snapshotFlow { EngineParam( cylinderQuantity = cacheState.getCylinderQuantity().value, inGapNormal = cacheState.getInGapNormal().value ) } } }
第四步:分层调用
- ViewModel只通过Domain层的
EngineParamRepository接口操作数据,不直接持有EngineViewState - 计算逻辑放在Domain层的UseCase中,依赖
EngineParamRepository接口获取数据,完全不需要感知UI层的状态实现细节
3. 特殊场景补充
如果你的需求只是单个页面的临时状态,不需要跨页面复用、也不需要持久化存储,也可以直接在ViewModel中持有这个状态,UI专属的计算逻辑也可以放在ViewModel中,不需要强行套Repository层逻辑,避免过度设计。
内容的提问来源于stack exchange,提问作者Илья Сумков
相关产品推荐
相关产品推荐

