Tailwind CSSTailwind CSS
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain

第6章:协议在模块化架构中的应用

6.3 模块间的通信机制

在模块化架构中,模块之间的通信是确保系统协作的关键环节。Swift 的协议化编程(POP)不仅用于定义模块接口,还可以通过协议设计灵活的通信机制,实现模块间的解耦和高效交互。本节将探讨模块间通信的常见方式,分析如何利用协议实现这些机制,并通过示例展示其在模块化系统中的应用。

模块间通信的需求

模块化架构要求模块独立,但实际应用中模块间需要交换数据或触发行为。例如:

  • 用户模块通知支付模块处理订单。
  • 数据模块向展示模块提供更新内容。

通信机制需要满足:

  • 松耦合:避免模块直接依赖具体实现。
  • 清晰性:通信接口明确,易于理解。
  • 灵活性:支持多种通信模式(如同步、异步)。

常见的通信机制

  1. 委托模式(Delegation):
    • 一个模块定义协议,另一个模块遵循并实现回调。
  2. 观察者模式(Observer):
    • 通过通知或事件广播实现一对多通信。
  3. 依赖注入与方法调用:
    • 通过注入的协议接口直接调用方法。
  4. 消息传递:
    • 使用队列或中间件传递数据。

在 Swift 中,协议可以无缝支持这些机制。

示例 1:委托模式

假设一个订单模块需要通知状态模块更新状态:

protocol OrderDelegate {
    func orderDidComplete(orderId: String)
}

class OrderManager {
    private let delegate: OrderDelegate?
    
    init(delegate: OrderDelegate?) {
        self.delegate = delegate
    }
    
    func processOrder(orderId: String) {
        print("Processing order \(orderId)")
        delegate?.orderDidComplete(orderId: orderId)
    }
}

class StatusManager: OrderDelegate {
    func orderDidComplete(orderId: String) {
        print("Status updated for order \(orderId)")
    }
}

let status = StatusManager()
let order = OrderManager(delegate: status)
order.processOrder(orderId: "o123")
// 输出:
// Processing order o123
// Status updated for order o123
  • OrderDelegate 定义通信接口。
  • OrderManager 通过委托通知 StatusManager,保持松耦合。

示例 2:观察者模式

使用通知中心实现多模块监听:

protocol EventObservable {
    func observe(event: String, handler: @escaping (String) -> Void)
    func notify(event: String, data: String)
}

class NotificationCenterAdapter: EventObservable {
    private var observers: [String: [(String) -> Void]] = [:]
    
    func observe(event: String, handler: @escaping (String) -> Void) {
        observers[event, default: []].append(handler)
    }
    
    func notify(event: String, data: String) {
        observers[event]?.forEach { $0(data) }
    }
}

class DataModule {
    private let observable: EventObservable
    
    init(observable: EventObservable) {
        self.observable = observable
    }
    
    func updateData(value: String) {
        observable.notify(event: "dataUpdated", data: value)
    }
}

class DisplayModule {
    private let observable: EventObservable
    
    init(observable: EventObservable) {
        observable.observe(event: "dataUpdated") { data in
            print("Display updated with: \(data)")
        }
    }
}

let center = NotificationCenterAdapter()
let data = DataModule(observable: center)
let display = DisplayModule(observable: center)
data.updateData(value: "New content")
// 输出: Display updated with: New content
  • EventObservable 定义观察者接口。
  • NotificationCenterAdapter 作为中间件,管理事件分发。

示例 3:依赖注入与方法调用

直接通过注入的协议接口通信:

protocol AnalyticsService {
    func trackEvent(_ event: String, parameters: [String: Any])
}

class UserManager {
    private let analytics: AnalyticsService
    
    init(analytics: AnalyticsService) {
        self.analytics = analytics
    }
    
    func login(userId: String) {
        print("User \(userId) logged in")
        analytics.trackEvent("login", parameters: ["userId": userId])
    }
}

struct ConsoleAnalytics: AnalyticsService {
    func trackEvent(_ event: String, parameters: [String: Any]) {
        print("Analytics: \(event) - \(parameters)")
    }
}

let analytics = ConsoleAnalytics()
let userManager = UserManager(analytics: analytics)
userManager.login(userId: "u456")
// 输出:
// User u456 logged in
// Analytics: login - ["userId": "u456"]
  • AnalyticsService 是通信接口,UserManager 通过注入调用方法。

异步通信支持

对于需要异步处理的场景,可以结合 Swift 的异步特性:

protocol AsyncDataProvider {
    func fetchData() async -> String
}

struct RemoteDataProvider: AsyncDataProvider {
    func fetchData() async -> String {
        await Task.sleep(1_000_000_000) // 模拟延迟 1 秒
        return "Remote data"
    }
}

class DataConsumer {
    private let provider: AsyncDataProvider
    
    init(provider: AsyncDataProvider) {
        self.provider = provider
    }
    
    func refresh() async {
        let data = await provider.fetchData()
        print("Consumed: \(data)")
    }
}

Task {
    let consumer = DataConsumer(provider: RemoteDataProvider())
    await consumer.refresh()
    // 输出: Consumed: Remote data(1 秒后)
}
  • AsyncDataProvider 定义异步接口,支持现代并发。

通信机制的选择

机制适用场景优点缺点
委托模式一对一通信简单直接不适合多接收者
观察者模式一对多广播灵活,支持动态订阅管理复杂,可能内存泄漏
方法调用直接同步通信高效,类型安全耦合稍高
异步通信需要延迟或并发处理支持现代异步特性实现稍复杂

测试通信机制

为 AnalyticsService 添加 Mock 测试:

struct MockAnalytics: AnalyticsService {
    var trackedEvents: [(String, [String: Any])] = []
    
    func trackEvent(_ event: String, parameters: [String: Any]) {
        trackedEvents.append((event, parameters))
    }
}

import XCTest
class UserManagerTests: XCTestCase {
    func testLoginTracksEvent() {
        let mockAnalytics = MockAnalytics()
        let manager = UserManager(analytics: mockAnalytics)
        
        manager.login(userId: "u789")
        XCTAssertEqual(mockAnalytics.trackedEvents.count, 1)
        XCTAssertEqual(mockAnalytics.trackedEvents[0].0, "login")
        XCTAssertEqual(mockAnalytics.trackedEvents[0].1["userId"] as? String, "u789")
    }
}
  • Mock 验证了 UserManager 的通信行为。

设计优势

  1. 解耦:模块通过协议通信,不依赖具体实现。
  2. 灵活性:支持多种通信模式,适应不同需求。
  3. 测试性:Mock 对象隔离通信逻辑,便于验证。

注意事项

  • 接口清晰:通信协议应简洁,避免过多参数。
  • 内存管理:观察者模式需注意弱引用,避免循环引用。
  • 一致性:确保通信行为在所有实现中一致。

小结

模块间的通信机制是模块化架构的纽带,协议通过定义通信接口实现了灵活性和解耦。本节展示了委托、观察者、方法调用和异步通信的应用,为模块化设计提供了多样化选择。下一节将通过实战案例整合这些概念,构建完整模块化系统。


Last Updated:: 3/11/25, 11:48 AM