4-28.【协议导向编程】如何用协议约束实现异步流水线或数据流处理?

2 阅读2分钟

一、核心原理

  1. 协议抽象能力

    • 每个流水线节点可以抽象成一个能力协议(例如 ProcessableAsyncStep
    • 模块间只依赖协议 → 解耦
  2. 协议扩展提供默认实现

    • 可提供模板方法、通用逻辑、错误处理
    • 类型可覆盖 → 灵活扩展
  3. 泛型 + 协议约束

    • 流水线节点类型用泛型约束协议 → 静态派发
    • 高性能零开销
    • 支持异步返回值(async/awaitCombine/AsyncSequence
  4. 组合能力

    • 节点可以组合多个协议能力 → 构建复杂数据流
    • 避免继承树 → 灵活拓展

二、设计策略

  1. 定义核心协议

    • 每个流水线节点遵循协议,提供输入 → 输出方法
    • 支持异步
  2. 扩展协议提供默认行为

    • 模板方法、日志、错误处理
    • 提高复用
  3. 泛型约束流水线

    • 核心管道逻辑不依赖具体节点类型
    • 保证高性能
  4. 组合节点形成流水线

    • 多协议 + 泛型组合 → 灵活组装
    • 支持异步链式调用

三、Swift 异步流水线示例

1️⃣ 定义异步处理协议

protocol AsyncStep {
    associatedtype Input
    associatedtype Output
    
    func process(_ input: Input) async throws -> Output
}

2️⃣ 提供默认扩展方法(可选)

extension AsyncStep {
    func loggingProcess(_ input: Input) async throws -> Output {
        print("Processing input: (input)")
        let result = try await process(input)
        print("Result: (result)")
        return result
    }
}

3️⃣ 实现具体节点

struct FetchData: AsyncStep {
    func process(_ input: String) async throws -> String {
        try await Task.sleep(nanoseconds: 500_000_000) // 模拟异步
        return "Data for (input)"
    }
}

struct ParseData: AsyncStep {
    func process(_ input: String) async throws -> [String] {
        input.split(separator: " ").map { String($0) }
    }
}

struct SaveData: AsyncStep {
    func process(_ input: [String]) async throws -> Bool {
        print("Saving: (input)")
        return true
    }
}

4️⃣ 构建泛型流水线

struct AsyncPipeline<Input, Output> {
    let steps: [(Input) async throws -> Output]
    
    func run(_ input: Input) async rethrows -> Output {
        var current = input
        for step in steps {
            current = try await step(current)
        }
        return current
    }
}

// 使用协议约束构建流水线
func makePipeline<S1: AsyncStep, S2: AsyncStep, S3: AsyncStep>(
    s1: S1, s2: S2, s3: S3
) -> AsyncPipeline<S1.Input, S3.Output> where S1.Output == S2.Input, S2.Output == S3.Input {
    AsyncPipeline(steps: [
        s1.process,
        s2.process,
        s3.process
    ])
}

5️⃣ 流水线运行示例

let pipeline = makePipeline(
    s1: FetchData(),
    s2: ParseData(),
    s3: SaveData()
)

Task {
    do {
        let result = try await pipeline.run("Order 123")
        print("Pipeline completed: (result)")
    } catch {
        print("Pipeline failed: (error)")
    }
}

✅ 特点:

  • 类型安全:泛型 + 协议约束确保输入输出匹配
  • 异步安全:支持 async/await
  • 可组合:节点可自由组合 → 构建复杂流水线
  • 可复用:新节点只需 conform 协议即可加入管道
  • 解耦:流水线核心逻辑不依赖具体实现

四、工程实践策略

策略说明
单一职责协议每个异步节点只处理一个能力
协议扩展提供模板方法可复用日志、错误处理等
泛型约束 + associatedtype保证类型安全 + 静态派发
节点组合 → 流水线灵活组装不同业务逻辑
异步支持 async/await高性能异步流水线
低耦合核心管道不依赖节点具体类型 → 易测试

五、设计口诀

“协议定义节点能力 → 扩展提供模板 → 泛型约束保证类型安全 → 节点组合成流水线 → 异步安全 + 可复用。”