如何用多态重构Activity/Fragment中含视图的复杂方法?
重构冗长的状态UI更新方法:替换条件判断为多态
问题背景
你当前的代码中,updateStatusFragmentUI方法包含大量基于ReceptionUiType的条件分支,每个分支处理不同状态下的UI配置,导致方法冗长、维护困难。核心代码如下:
private fun updateStatusFragmentUI(statusData: StatusListData.StatusData) = with(binding.detail) { with(statusData) { tvCodeDoc.text = getString(R.string.reception_code).format(receptionKey) tvTime.text = createdAt.toFullTimeString() tvName.text = name tvContact.text = phoneNumber tvAddress.text = address tvAddressOld.text = addressOld btnSubAction.isVisible = false contentsRead.root.isVisible = false contentsWrite.root.isVisible = false footerAction.root.isVisible = false footerInformation.root.isVisible = false when (detailStatus) { ReceptionUiType.PRICE_REQUEST -> { btnSubAction.setText(R.string.reception_cancel) btnSubAction.isVisible = viewModel.isCancelButtonVisible btnSubAction.setOnClickListener { showDialogReceptionCancel(false) } setWriteContents(this) setActionFooter(R.string.all_send_price) } // 其他大量分支... else -> { /* no-op */ } } } }
重构方案:替换条件判断为多态
1. 类命名建议
避免使用Manager这类模糊命名,推荐贴合职责的命名:
- 核心接口:
ReceptionUiRenderer(明确职责是渲染对应状态的UI) - 实现类:
[状态名]UiRenderer(如PriceRequestUiRenderer、PaymentWaitUiRenderer) - 工厂类:
ReceptionUiRendererFactory(负责创建对应状态的Renderer实例) - 弹窗操作抽象:
ReceptionDialogHandler(解耦Renderer与Fragment的弹窗依赖)
2. 步骤分解
第一步:抽象弹窗操作接口
将Fragment中的弹窗方法抽象为接口,避免Renderer直接依赖Fragment:
interface ReceptionDialogHandler { fun showDialogReceptionCancel(isDispensing: Boolean) fun showDialogDispensingCancel() }
让你的Fragment实现该接口:
class YourStatusFragment : Fragment(), ReceptionDialogHandler { override fun showDialogReceptionCancel(isDispensing: Boolean) { // 原弹窗实现逻辑 } override fun showDialogDispensingCancel() { // 原弹窗实现逻辑 } // 其他Fragment方法... }
第二步:定义UI渲染核心接口
创建Renderer接口,定义渲染UI的标准方法:
interface ReceptionUiRenderer { fun render( detailBinding: DetailBinding, // 对应binding.detail的实际类型 statusData: StatusListData.StatusData, viewModel: YourViewModel, dialogHandler: ReceptionDialogHandler ) }
第三步:为每个状态创建Renderer实现类
每个ReceptionUiType对应一个Renderer类,封装该状态下的UI逻辑:
// PRICE_REQUEST状态的Renderer示例 class PriceRequestUiRenderer : ReceptionUiRenderer { override fun render( detailBinding: DetailBinding, statusData: StatusListData.StatusData, viewModel: YourViewModel, dialogHandler: ReceptionDialogHandler ) { with(detailBinding) { btnSubAction.setText(R.string.reception_cancel) btnSubAction.isVisible = viewModel.isCancelButtonVisible btnSubAction.setOnClickListener { dialogHandler.showDialogReceptionCancel(false) } setWriteContents(statusData) setActionFooter(R.string.all_send_price) } } } // PAYMENT_WAIT状态的Renderer示例 class PaymentWaitUiRenderer : ReceptionUiRenderer { override fun render( detailBinding: DetailBinding, statusData: StatusListData.StatusData, viewModel: YourViewModel, dialogHandler: ReceptionDialogHandler ) { with(detailBinding) { btnSubAction.setText(R.string.reception_cancel) btnSubAction.isVisible = viewModel.isCancelButtonVisible btnSubAction.setOnClickListener { dialogHandler.showDialogReceptionCancel(false) } setReadContents(statusData) contentsRead.clDuration.isVisible = false setInformationFooter( R.string.include_detail_info_payment_method_title, R.string.include_detail_info_payment_method_sub_title ) } } } // 其他状态依次实现对应的Renderer... // 默认Renderer,处理未定义的状态 class DefaultReceptionUiRenderer : ReceptionUiRenderer { override fun render(...) { // 空实现或设置默认UI } }
第四步:创建Renderer工厂类
通过工厂类根据状态类型返回对应的Renderer实例:
object ReceptionUiRendererFactory { fun getRenderer(type: ReceptionUiType): ReceptionUiRenderer { return when(type) { ReceptionUiType.PRICE_REQUEST -> PriceRequestUiRenderer() ReceptionUiType.PAYMENT_WAIT -> PaymentWaitUiRenderer() ReceptionUiType.DISPENSING_WAIT -> DispensingWaitUiRenderer() // 其他状态一一映射 else -> DefaultReceptionUiRenderer() } } }
第五步:简化原UI更新方法
提取公共UI初始化逻辑,通过工厂获取Renderer完成状态特有UI渲染:
private fun updateStatusFragmentUI(statusData: StatusListData.StatusData) = with(binding.detail) { with(statusData) { // 所有状态共享的UI初始化 tvCodeDoc.text = getString(R.string.reception_code).format(receptionKey) tvTime.text = createdAt.toFullTimeString() tvName.text = name tvContact.text = phoneNumber tvAddress.text = address tvAddressOld.text = addressOld btnSubAction.isVisible = false contentsRead.root.isVisible = false contentsWrite.root.isVisible = false footerAction.root.isVisible = false footerInformation.root.isVisible = false } // 获取对应Renderer并渲染状态特有UI val renderer = ReceptionUiRendererFactory.getRenderer(statusData.detailStatus) renderer.render( detailBinding = this, statusData = statusData, viewModel = viewModel, dialogHandler = this@YourStatusFragment ) }
重构优势
- 职责单一:每个Renderer类只负责对应状态的UI逻辑,代码更易理解和维护
- 开闭原则:新增状态时只需添加新的Renderer类和工厂映射,无需修改原方法
- 解耦:通过抽象接口分离UI渲染逻辑与Fragment、ViewModel的依赖
内容的提问来源于stack exchange,提问作者c-an
相关产品推荐
相关产品推荐

