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

遵循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,提问作者Илья Сумков

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 11:27:04