Swift如何重构带where子句的Savable与Downloadable协议消除冗余?
重复代码的产生根源
- Swift 协议扩展中实现的方法默认采用静态分派,只有在协议本体中正式声明的方法要求,才会通过协议见证表实现动态分派。
- 原代码中所有版本的
save()都仅实现于协议扩展中,属于静态绑定方法。如果只保留Downloadable的无约束扩展实现,在该上下文环境中编译器能静态匹配到的只有无约束版本的save(),不会根据Self实际的遵循约束自动切换到C1、C1 & C2版本的save(),这就是必须重复编写三份和save()约束完全对应的download()实现的根本原因。
消除重复代码的实现方案
核心逻辑是将save()从静态扩展方法升级为协议本体声明的动态分派要求,打通跨约束的调用链路,让无约束上下文里的save()调用可以自动匹配当前类型的对应实现,完全不需要为Downloadable编写带约束的重复扩展。
实现步骤完全符合现有架构限制:
- 不改变
Savable、Downloadable的协议形式 - 不引入运行时的遵循状态检查(适配
C1、C2带Self/关联类型要求的限制)
- 修改
Savable协议本体定义,将save()列为协议的正式方法要求 - 保留所有原有针对不同约束的
save()扩展实现,这些实现会自动编译进对应遵循类型的协议见证表,实现动态分派 - 删除
Downloadable上所有带where Self:约束的重复download()扩展,仅保留基础无约束版本的实现即可
修改后的完整可运行代码如下:
// 原有约束定义保持不变 protocol C1 { } protocol C2 { } // 调整后的Savable协议:正式声明save()为协议要求 protocol Savable { func save() } // 原有save()的多版本约束实现完全保留 extension Savable { func save() { print("Perform basic save") } } extension Savable where Self: C1 { func save() { print("Perform save C1") } } extension Savable where Self: C1 & C2 { func save() { print("Perform save C1 & C2") } } // 简化后的Downloadable:删除所有重复的带约束扩展 protocol Downloadable: Savable { } extension Downloadable { func download() { print("Perform download") save() } } // 原有测试用例保持不变,输出结果与原代码完全一致 class MyClassC1: Downloadable, C1 { } let obj1 = MyClassC1() obj1.download() // 输出结果: // Perform download // Perform save C1 class MyClassC1C2: Downloadable, C1, C2 { } let obj2 = MyClassC1C2() obj2.download() // 输出结果: // Perform download // Perform save C1 & C2
方案验证
- 整个匹配流程完全在编译期完成方法表绑定,不需要运行时检测
Self对C1、C2的遵循状态,完全适配约束协议不能做运行时检查的限制 - 架构层面始终保持
Savable、Downloadable的纯协议定义,没有引入类、枚举等实体类型,满足原有架构约束 - 所有原有方法的约束匹配规则、输出行为和原代码完全一致,没有逻辑变更
内容的提问来源于stack exchange,提问作者Lee Kah Seng
相关产品推荐
相关产品推荐

