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

如何用多态重构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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 02:09:08