4-24.【协议导向编程】当一个协议需要频繁扩展方法时,你会采用哪些设计策略?

0 阅读2分钟

一、核心原则

  1. 协议只抽象核心行为

    • 避免把大量工具方法直接加到协议中
    • 核心方法 → 多态点
    • 可复用辅助方法 → 放到 protocol extension 或独立协议
  2. 用扩展(extension)提供默认实现,而非直接修改协议

    • extension 方法默认静态派发 → 不破坏已有多态
    • conforming 类型可覆盖
  3. 分层设计 → 多协议组合

    • 将能力拆成多个小协议
    • 高层类型按需组合 → 避免单个协议过大
  4. 慎用 protocol 类型调用

    • 在高性能核心路径使用泛型 + 协议约束 → 静态派发
    • protocol existentials 只在非核心路径 / 可测试场景使用

二、具体设计策略

1️⃣ 核心协议 + 辅助扩展

protocol PaymentProcessor {
    func process(amount: Double)  // 核心多态方法
}

extension PaymentProcessor {
    func log(amount: Double) {   // 辅助方法,静态派发
        print("Logging payment: (amount)")
    }
}
  • process → 核心多态点 → conforming 类型可覆盖
  • log → 工具方法 → 默认实现可复用

2️⃣ 多协议拆分能力

protocol Refundable {
    func refund(amount: Double)
}

protocol Trackable {
    func trackEvent(name: String)
}

// 组合类型
struct CreditCardProcessor: PaymentProcessor, Refundable, Trackable {
    func process(amount: Double) { print("Processing (amount)") }
    func refund(amount: Double) { print("Refund (amount)") }
    func trackEvent(name: String) { print("Tracking (name)") }
}
  • 每个协议只关注一个能力
  • 组合使用 → 避免单个协议膨胀

3️⃣ 默认实现 + 模板方法

extension PaymentProcessor {
    func execute(amount: Double) {
        preProcess()
        process(amount: amount)
        postProcess()
    }

    func preProcess() { print("Default pre-processing") }
    func postProcess() { print("Default post-processing") }
}
  • 核心方法 process → 多态点
  • 模板方法 execute → 静态派发,可复用
  • 高层 conforming 类型只需覆盖必要方法 → 灵活可扩展

4️⃣ 泛型 + 协议约束保持性能

func makePayment<P: PaymentProcessor>(processor: P, amount: Double) {
    processor.execute(amount: amount) // 静态派发
}
  • 泛型约束协议 → 零开销抽象
  • 高性能路径避免 protocol 类型调用

5️⃣ 工程级策略总结

策略说明
核心方法与辅助方法分开核心多态点在协议中,工具方法放 extension
多协议拆分能力避免协议过大,增强组合灵活性
模板方法 / 默认实现可复用逻辑,类型可覆盖
泛型约束协议保证静态派发,高性能
避免存在大量 protocol 类型调用existentials 动态派发有开销,慎用在核心逻辑

六、设计口诀

“核心行为声明在协议 → 多态点;
辅助逻辑放扩展 → 静态派发;
拆分协议 → 能力组合;
泛型约束 → 零开销抽象。”