4-26.【协议导向编程】在复杂业务模块中,如何使用 POP 构建可组合的功能单元?

3 阅读2分钟

一、核心思想

POP 的关键理念是:

  1. 协议 = 能力契约

    • 每个功能单元对应一个协议,描述它能做什么
  2. 协议扩展 = 默认实现

    • 提供通用行为模板
    • 类型可以选择覆盖
  3. 类型组合协议 = 功能组合

    • struct / class 可以 conform 多个协议 → 多能力组合
    • 避免深层继承树
  4. 泛型 + 协议约束 = 高性能抽象

    • 核心逻辑走泛型静态派发
    • 可复用模板方法

二、设计原则

  1. 单一职责协议

    • 每个协议只抽象一个能力
    • 避免“大协议”承载过多功能
  2. 模块化能力

    • 将协议按功能模块组织
    • 高层协议可以组合多个基础协议
  3. 默认实现 + 覆盖机制

    • 常用逻辑放在扩展中
    • 需要定制时覆盖
  4. 值类型组合

    • struct 可组合多个协议 → 轻量高性能
    • 支持灵活复用

三、典型 Swift 示例:电商订单模块

假设我们有一个复杂订单系统,需要支持 支付、日志记录、通知、折扣计算

1️⃣ 定义基础能力协议

protocol Payable {
    func pay(amount: Double)
}

protocol Discountable {
    func applyDiscount(amount: Double) -> Double
}

protocol Notifiable {
    func notify(message: String)
}

protocol Loggable {
    func log(message: String)
}

2️⃣ 提供默认实现(模板方法)

extension Discountable {
    func applyDiscount(amount: Double) -> Double {
        // 默认不打折
        return amount
    }
}

extension Notifiable {
    func notify(message: String) {
        print("Notification: (message)")
    }
}

extension Loggable {
    func log(message: String) {
        print("Log: (message)")
    }
}

3️⃣ 组合功能单元

struct Order: Payable, Discountable, Notifiable, Loggable {
    func pay(amount: Double) {
        let finalAmount = applyDiscount(amount: amount)
        log(message: "Paying (finalAmount)")
        notify(message: "Paid (finalAmount)")
    }
    
    // 可以覆盖默认折扣逻辑
    func applyDiscount(amount: Double) -> Double {
        return amount * 0.9
    }
}

4️⃣ 使用示例

let order = Order()
order.pay(amount: 100)
// 输出:
// Log: Paying 90.0
// Notification: Paid 90.0

✅ 特点:

  • 功能单元可组合 → Payable、Discountable、Notifiable、Loggable
  • 核心逻辑高性能 → pay() 使用静态派发
  • 扩展灵活 → 可覆盖默认折扣或通知逻辑

四、工程级实践策略

策略说明
单一职责协议每个协议只描述一个能力,避免膨胀
模块化协议按功能域组织协议,便于查找与复用
默认实现放通用行为,类型可选择覆盖
高阶组合协议组合多个基础协议形成复合能力
泛型约束核心逻辑保证高性能,避免 protocol 类型动态派发开销
结构体组合值类型组合能力 → 灵活 + 轻量

五、设计口诀

“每个能力一个协议 → 默认实现提供模板 → 类型自由组合 → 泛型静态派发 → 高性能复用。”