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

第3章:协议扩展(Protocol Extensions)

3.5 实战案例:通过协议扩展实现通用功能

协议扩展不仅是一个理论工具,更是实际开发中提升代码复用性和模块化的利器。在本节中,我们将通过一个实战案例展示如何利用协议扩展实现通用功能。具体来说,我们将设计一个简单的“通知系统”,通过协议和扩展为不同类型的对象提供通知发送和日志记录功能。这一案例将综合运用协议定义、默认实现和条件约束,体现协议化编程(POP)的实用价值。

案例背景

假设我们要开发一个应用,需要在某些事件发生时发送通知(例如打印到控制台或写入文件),并记录事件日志。通知的发送方式和日志格式可能因对象类型而异,但我们希望核心逻辑可以复用。我们将使用协议扩展来实现这一目标。

设计协议

首先,定义两个核心协议:一个用于通知,一个用于日志记录。

// 表示可发送通知的对象
protocol Notifiable {
    var identifier: String { get }
    func sendNotification(message: String)
}

// 表示可记录日志的对象
protocol Loggable {
    var logPrefix: String { get }
    func log(_ event: String)
}
  • Notifiable 定义了通知的基本要求:标识符和发送方法。
  • Loggable 定义了日志记录的要求:前缀和记录方法。

添加默认实现

通过协议扩展为这两个协议提供默认实现:

extension Notifiable {
    func sendNotification(message: String) {
        print("Notification from \(identifier): \(message)")
    }
}

extension Loggable {
    func log(_ event: String) {
        print("\(logPrefix) - \(event) at \(Date())")
    }
}
  • sendNotification 默认将通知打印到控制台。
  • log 默认记录事件和时间戳。

实现具体类型

现在,创建几个遵循这些协议的具体类型:

// 表示用户,遵循 Notifiable
struct User: Notifiable {
    var identifier: String
}

// 表示设备,遵循 Notifiable 和 Loggable
struct Device: Notifiable, Loggable {
    var identifier: String
    var logPrefix: String {
        return "[Device \(identifier)]"
    }
    
    // 自定义通知发送方式
    func sendNotification(message: String) {
        print("Device \(identifier) alert: \(message)")
    }
}

let user = User(identifier: "alice")
let device = Device(identifier: "dev001")

user.sendNotification(message: "Welcome!")     
// 输出: Notification from alice: Welcome!

device.sendNotification(message: "Low battery") 
// 输出: Device dev001 alert: Low battery

device.log("Started")                           
// 输出: [Device dev001] - Started at [当前时间]
  • User 使用 Notifiable 的默认实现。
  • Device 覆盖了 sendNotification,但复用了 Loggable 的默认实现。

使用 where 子句增强功能

假设我们想为支持日志记录的通知对象添加额外功能,例如记录通知发送事件。可以使用 where 子句约束扩展:

extension Notifiable where Self: Loggable {
    func sendAndLog(message: String) {
        sendNotification(message: message)
        log("Notification sent: \(message)")
    }
}

// 只有 Device 能使用此方法,因为它同时遵循 Notifiable 和 Loggable
device.sendAndLog(message: "Update available")
// 输出:
// Device dev001 alert: Update available
// [Device dev001] - Notification sent: Update available at [当前时间]

// user.sendAndLog() // 编译错误:User 未遵循 Loggable
  • sendAndLog 结合了通知和日志功能,仅对同时遵循 Notifiable 和 Loggable 的类型生效。

添加更复杂的通用功能

我们可以进一步扩展功能,例如为通知添加优先级支持:

protocol Prioritized {
    var priority: Int { get }
}

extension Notifiable where Self: Prioritized {
    func sendPriorityNotification(message: String) {
        let prefix = priority > 5 ? "[HIGH]" : "[LOW]"
        sendNotification(message: "\(prefix) \(message)")
    }
}

struct AlertDevice: Notifiable, Loggable, Prioritized {
    var identifier: String
    var logPrefix: String { "[Alert \(identifier)]" }
    var priority: Int
}

let alert = AlertDevice(identifier: "alert001", priority: 7)
alert.sendPriorityNotification(message: "System failure")
// 输出: Notification from alert001: [HIGH] System failure

alert.sendAndLog(message: "Maintenance scheduled")
// 输出:
// Notification from alert001: Maintenance scheduled
// [Alert alert001] - Notification sent: Maintenance scheduled at [当前时间]
  • Prioritized 协议添加了优先级要求。
  • sendPriorityNotification 根据优先级动态调整通知格式,仅对支持优先级的类型生效。

案例分析:协议扩展的优势

  1. 复用性:默认实现(如 sendNotification 和 log)避免了重复代码。
  2. 灵活性:遵循者可以覆盖默认实现(Device 的通知)或使用扩展功能(sendAndLog)。
  3. 模块化:通过 where 子句,功能被精确分配给符合条件的类型。
  4. 类型安全:Swift 的类型系统确保只有满足条件的类型才能访问特定扩展。

优化与分派考虑

  • 静态分派:通过具体类型调用(如 device.sendNotification)使用静态分派,性能高效。
  • 动态分派:通过协议类型调用(如 let n: Notifiable = device)会触发动态分派,可能有轻微开销。
  • 建议:在性能敏感场景中,尽量使用具体类型调用扩展方法。

注意事项

  • 依赖清晰:扩展中的默认实现应只依赖协议要求的数据(如 identifier 和 logPrefix)。
  • 功能边界:避免在扩展中添加过于复杂的逻辑,以保持可维护性。
  • 测试覆盖:为默认实现和覆盖实现编写单元测试,确保行为一致。

小结

通过这个通知系统案例,我们展示了如何利用协议扩展实现通用功能。默认实现提供了基础行为,where 子句增强了条件适配性,而不同类型的遵循者则展示了灵活性。这种设计体现了 POP 的核心思想:抽象行为、复用逻辑、松耦合。下一章将探讨协议与泛型的结合,进一步扩展这些概念的应用范围。


Last Updated:: 3/10/25, 2:58 PM