4-22.【协议导向编程】如何设计协议,使其既能抽象业务逻辑,又不影响性能?

0 阅读2分钟

一、核心原理

  1. 协议本身不影响性能

    • 协议声明仅定义行为契约 → 无开销
  2. 默认实现(protocol extension)默认静态派发

    • 静态派发零开销 → 高性能
  3. 协议类型调用 (existential)

    • 通过变量存协议类型 → 动态派发 → 有少量运行时开销
  4. 泛型 + 协议约束

    • 在编译期决定类型 → 静态派发 → 零开销抽象

结论

  • 想抽象业务逻辑 + 高性能 → 用泛型约束协议
  • 偶尔 protocol 类型 existentials → 接受少量开销
  • 默认实现可用于模板 / 工具方法 → 不影响核心性能

二、设计策略

1️⃣ 核心业务逻辑 → 协议 + 泛型约束

  • 协议只声明必需行为
  • 使用泛型约束协议 → 静态派发
protocol PaymentProcessor {
    func process(amount: Double)
}

struct CreditCardProcessor: PaymentProcessor {
    func process(amount: Double) {
        print("Processing credit card: (amount)")
    }
}

struct ApplePayProcessor: PaymentProcessor {
    func process(amount: Double) {
        print("Processing ApplePay: (amount)")
    }
}

func makePayment<P: PaymentProcessor>(processor: P, amount: Double) {
    processor.process(amount: amount) // 静态派发 ✅
}

✅ 泛型 + 协议 → 零开销抽象


2️⃣ 可选复用逻辑 → protocol extension

extension PaymentProcessor {
    func log(amount: Double) {
        print("Logging payment: (amount)")
    }
}
  • 默认实现静态派发 → 零开销
  • conforming 类型可覆盖 → 灵活

3️⃣ 仅在必要时使用 protocol 类型(existential)

let processors: [any PaymentProcessor] = [CreditCardProcessor(), ApplePayProcessor()]

for p in processors {
    p.process(amount: 100) // 动态派发,略有开销
}
  • 存在少量动态派发
  • 在高性能核心路径尽量避免

4️⃣ 分离“核心高性能逻辑”和“抽象逻辑”

  • 核心计算 → 泛型 + 协议约束 → 静态派发
  • 可替换 / 测试逻辑 → protocol 类型 + 默认实现 → 灵活
protocol Calculator {
    func compute(_ x: Int) -> Int
}

extension Calculator {
    func debugCompute(_ x: Int) -> Int {
        print("Computing (x)")
        return compute(x)
    }
}

struct FastCalculator: Calculator {
    func compute(_ x: Int) -> Int { x * 2 }
}
  • compute → 高性能
  • debugCompute → 可复用、可扩展

5️⃣ 工程级设计原则

原则说明
协议声明少量核心行为避免协议中方法过多 → witness table 更小
泛型 + 协议约束静态派发,高性能
protocol extension 提供默认实现可复用模板方法 → 静态派发
protocol 类型调用少用在核心路径动态派发略有开销,尽量在 IO/UI/测试使用
分层设计核心计算 → 泛型;抽象逻辑 → protocol 类型

六、总结口诀

“核心逻辑泛型 + 协议约束 → 零开销;
模板方法扩展 → 可复用;
协议类型调用仅在非核心路径 → 可测试解耦。”