SwiftUI项目中如何泛化多个存在重复逻辑的ViewModel?
解决方案
你可以通过以下两种常用方案实现代码复用:
方案1:泛型基类继承(最贴合你的初始需求)
直接定义通用泛型父类,把可变的选择类型作为泛型参数,所有公共逻辑统一放在父类实现,子类仅需定义独有业务内容即可:
// 通用基类 class BaseViewModel<SelectionType>: ObservableObject { @Published var selected: SelectionType? func select(_ value: SelectionType?) { selected = value } } // 业务子类A class ViewModelA: BaseViewModel<ViewModelA.Animal> { enum Animal { case cat case dog } // 仅需编写ViewModelA独有的逻辑 } // 业务子类B class ViewModelB: BaseViewModel<ViewModelB.Animal> { enum Animal { case lion case tiger } // 仅需编写ViewModelB独有的逻辑 }
该方案代码量最少,完全复用父类的属性与方法实现,不需要重复编写公共逻辑。
方案2:带关联类型的协议实现(适用无法使用继承的场景)
虽然Swift协议不能直接声明属性包装器,但可以声明@Published生成的对应属性,再通过协议扩展提供默认方法实现:
// 通用协议定义 protocol SelectableViewModel: ObservableObject { associatedtype SelectionType var selected: SelectionType? { get set } var $selected: Published<SelectionType?>.Publisher { get } } // 协议默认实现公共方法 extension SelectableViewModel { func select(_ value: SelectionType?) { selected = value } } // 业务实现A class ViewModelA: SelectableViewModel { enum Animal { case cat case dog } // 添加@Published标记即可自动满足协议要求 @Published var selected: Animal? // 其他独有逻辑 } // 业务实现B class ViewModelB: SelectableViewModel { enum Animal { case lion case tiger } @Published var selected: Animal? // 其他独有逻辑 }
注意:你示例代码中的
@published为拼写错误,正确的属性包装器名称为首字母大写的@Published。
内容的提问来源于stack exchange,提问作者G. Marc
相关产品推荐
相关产品推荐

