Android中如何向视图传递信息?是否应遵循Tell-Don't-ask原则?
问题背景与疑问
我正在开发一款矩阵计算器Android应用,计算结果通过密封类ResultState表示:
sealed class ResultState { abstract fun showInfo(textView: TextView) data class SuccessState(private val matrixEntity: MatrixEntity): ResultState() { override fun showInfo(textView: TextView) { textView.text = matrixEntity.showMatrix() } } data class ErrorState(private val error: String = "Error"): ResultState() { override fun showInfo(textView: TextView) { textView.text = error } } object Default: ResultState() { override fun showInfo(textView: TextView) { textView.text = "Hello" } } }
同时MatrixEntity实现了Operators接口:
interface Operators { fun sum(matrixEntity: MatrixEntity): MatrixEntity fun diff(matrixEntity: MatrixEntity): MatrixEntity fun multiply(matrixEntity: MatrixEntity): MatrixEntity fun showMatrix(): String } data class MatrixEntity( private val numbers: List<List<Int>>, ) : Operators { // sum、diff、multiply方法的实现代码 override fun showMatrix(): String { var str = "" for (i in 0 until rows) { for (j in 0 until columns) { str += "${returnNumber(i,j)} " } str += "\n" } return str } }
我为保持类字段私有,创建showInfo方法向TextView传递信息,认为符合封装原则。但有Java商业开发经验的朋友指出这种方式打断了数据流,且因字段不可变,建议将字段设为公开直接向视图提供信息。我OOP经验不足,想请教:
- 在Android中应如何向视图提供信息?
- 是否应遵循Tell-Don't-ask原则?
解答
1. Android中向视图提供信息的合理方式
Android开发里,数据层和视图层的解耦是核心原则之一,两种思路都有适用场景,但更推荐分层处理:
- 别让数据类直接持有视图操作逻辑:
ResultState里的showInfo方法直接操作TextView,会把数据层和UI层强耦合,后续如果要更换展示方式(比如用Jetpack Compose代替传统TextView),或者在其他地方复用ResultState,都会变得异常麻烦。 - 数据类只负责提供数据,视图层负责渲染:把
ResultState的字段改为公开(或者通过getter暴露),让视图层拿到数据后自行处理渲染逻辑。比如SuccessState公开matrixEntity,视图层调用它的showMatrix()方法获取字符串再设置给TextView。
2. Tell-Don't-ask原则的正确应用
Tell-Don't-ask的核心是“告诉对象做什么,而不是询问对象状态再自己做”,但这一原则要分场景使用:
- 你的
showInfo方法看似符合Tell-Don't-ask,但问题在于它把“渲染UI”这个属于视图层的职责交给了数据类,违背了单一职责原则。数据类的职责是承载和处理业务数据,而非操作UI组件。 - 正确的做法是:数据类告诉视图层“我有什么数据”,视图层自己决定怎么渲染。比如
ResultState作为状态载体,暴露自身的状态数据(成功时的矩阵、错误时的提示文本),视图层拿到这些数据后执行渲染操作——这既没有破坏封装(你依然可以把MatrixEntity的内部numbers字段私有,只通过showMatrix()暴露格式化后的字符串),也遵循了分层职责。
3. 封装与数据流的权衡
- 封装的核心是隐藏内部实现细节,而非完全禁止暴露数据。
MatrixEntity把numbers私有,只通过showMatrix()提供格式化后的结果,这已经是良好的封装。而ResultState作为状态容器,暴露自身的状态数据(比如SuccessState的matrixEntity),并不会破坏封装,因为它暴露的是业务层面的状态,而非内部实现。 - 所谓“打断数据流”,本质是指
showInfo方法把数据流转的逻辑封闭在了数据类内部,视图层无法感知数据变化,也无法灵活处理展示逻辑。让状态类公开数据,能让数据流更清晰:从数据层产生ResultState,传递到视图层,视图层根据状态类型渲染对应UI。
内容的提问来源于stack exchange,提问作者Eldar Orudzhev
相关产品推荐
相关产品推荐

