Kotlin开发中能否总是用private set替代private val?StateFlow写法疑问
问题1:Code B的写法是否合理?
结论是不合理,两种写法的核心设计目的完全不同:
- Code A的设计逻辑是遵循单向数据流原则:
内部持有可变的MutableStateFlow类型的_uiState,可在内部修改状态;对外暴露的是不可变的StateFlow类型的uiState,外部只能订阅状态,无法修改,从类型层面保证了状态修改权仅在内部持有,避免状态混乱。
对应代码:private val _uiState = MutableStateFlow(InterestsUiState(loading = true)) val uiState: StateFlow<InterestsUiState> = _uiState.asStateFlow() - Code B的写法存在本质缺陷:
你对外暴露的uiState本身就是MutableStateFlow类型,private set仅能限制外部不能重新给uiState变量赋值,但无法限制外部调用uiState.value = xxx、uiState.update { }等方法修改流内部的状态,完全破坏了单向数据流的封装性,外部任意位置都能篡改状态,后期排查问题难度会非常高。
对应代码:var uiState = MutableStateFlow(InterestsUiState(loading = true)) private set
问题2:能否总是用private set替代private val加对外暴露不可变类型的模式?
结论是不能,两种写法适用的场景完全不同:
private set适合的场景:属性本身是不可变类型(比如Int、String、不可变集合List、不可变流StateFlow等),或者你允许外部访问到可变对象本身、仅限制外部不能替换变量指向的对象。
比如下面的写法是合理的:// 基本不可变类型,private set限制外部修改 var count: Int = 0 private set // 对外暴露不可变List,private set限制外部替换集合对象 var dataList: List<String> = emptyList() private set- 当你需要对外隐藏可变对象的修改能力时,必须使用
内部私有可变变量 + 对外暴露不可变父类类型的模式,private set完全无法满足这个需求,除了StateFlow之外,可变集合、LiveData等场景都遵循这个规则:// 可变集合的正确封装写法 private val _dataList = mutableListOf<String>() val dataList: List<String> = _dataList // 对外暴露不可变的List类型
内容的提问来源于stack exchange,提问作者HelloCW
相关产品推荐
相关产品推荐

