ViewModel 重构检查清单
识别坏味道:
1.直接访问全局变量(kIsVip)
2.一个类承担了太多职责(数据处理,插入广告,Vip状态)
3.函数长度超过 50 行
4.太多 mutable var(状态混乱)
5.直接使用单例 (BannerADHelp.shared、MainDataHelp.shared)
提取Input/Output:
定义 Input(所有外部传入的依赖)
定义 Output(View 需要显示的数据)
定义 ViewModel
定义协议(依赖倒置)
黄金法则: 每个外部依赖都要有协议
3.1 列出所有外部依赖 (BannerADHelp.shared Device.isIpad kIsVip)
3.2 为每个创建协议
protocol AdServiceProtocol {
func canRequestAD(for enter: ADEnterType) -> Bool
func getAdModel() -> ComponentADModel
}
// 3.3 创建真实实现(包装原有代码)
class DefaultAdService: AdServiceProtocol {
func canRequestAD(for enter: ADEnterType) -> Bool {
BannerADHelp.shared.canRequestAD(enter: enter) // 🔥 只在这里调用
}
}
处理条件判断
坏味道就是一堆 if-else

编写测试
测试是重构的保障!
// 6.1 创建 Mock
class MockAdService: AdServiceProtocol {
var canRequestADResult = false
func canRequestAD(for enter: ADEnterType) -> Bool {
return canRequestADResult
}
}
使用:
let mockAd = MockAdService()
mockAd.canRequestADResult = true
📚 记住这个口诀
找出依赖 → 定义协议
创建 Input → 注入依赖
分离职责 → 一个类做一件事
计算属性 → 替代存储属性
写测试 → 验证重构正确
最后建议
不要一次全改:先抽最简单的依赖(如Device.isIpad)
写一个测试用例:确保重构后功能不变
逐步替换:先用新 ViewModel 在简单页面
团队同步:和大家分享你的重构模式
核心思想:ViewModel 应该像函数一样——输入明确,输出明确,不依赖全局状态。每次写 ViewModel 时问问自己:“这个类能在测试中单独运行吗?”