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

第9章:协议化编程的优化与实践

9.4 综合案例:优化一个协议化的日志系统

在前几节中,我们探讨了协议化编程的性能优化、内存管理和最佳实践。本节将通过一个综合案例,将这些知识整合应用,设计并优化一个协议化的日志系统。该系统将展示如何利用协议实现模块化设计,同时优化性能和内存使用,最终形成一个灵活、可扩展的解决方案。

案例背景

我们要开发一个日志系统,支持以下功能:

  • 记录不同级别的日志(如 Info、Error)。
  • 支持多种输出目标(如控制台、文件)。
  • 提供格式化日志的能力。
  • 确保性能高效和内存管理合理。

目标是:

  • 使用协议实现松耦合。
  • 优化动态分派和内存开销。
  • 遵循最佳实践。

第一步:初始设计

定义核心协议和实现:

protocol Logger {
    func log(level: String, message: String)
}

struct ConsoleLogger: Logger {
    func log(level: String, message: String) {
        print("[\(level)] \(message)")
    }
}

struct LogManager {
    private let logger: Logger
    
    init(logger: Logger) {
        self.logger = logger
    }
    
    func info(_ message: String) {
        logger.log(level: "INFO", message: message)
    }
    
    func error(_ message: String) {
        logger.log(level: "ERROR", message: message)
    }
}

let manager = LogManager(logger: ConsoleLogger())
manager.info("App started") // 输出: [INFO] App started
manager.error("Failed to load") // 输出: [ERROR] Failed to load
  • 问题分析:
    • Logger 使用动态分派,性能可能受影响。
    • 单协议设计职责不清晰。
    • 扩展性有限,格式化需手动处理。

第二步:优化协议设计

根据最佳实践,重构为多个简洁协议:

/// 日志级别定义
enum LogLevel: String {
    case info = "INFO"
    case error = "ERROR"
}

/// 日志输出协议
protocol LogOutput {
    func write(_ text: String)
}

/// 日志格式化协议
protocol LogFormatter {
    func format(level: LogLevel, message: String) -> String
}

/// 默认格式化实现
struct DefaultFormatter: LogFormatter {
    func format(level: LogLevel, message: String) -> String {
        "[\(level.rawValue)] \(message)"
    }
}

/// 控制台输出
struct ConsoleOutput: LogOutput {
    func write(_ text: String) {
        print(text)
    }
}
  • 分离 LogOutput 和 LogFormatter,职责单一。
  • DefaultFormatter 提供默认实现。

第三步:优化业务逻辑

使用泛型和依赖注入优化 LogManager:

struct LogManager<Output: LogOutput, Formatter: LogFormatter> {
    private let output: Output
    private let formatter: Formatter
    
    init(output: Output, formatter: Formatter) {
        self.output = output
        self.formatter = formatter
    }
    
    func info(_ message: String) {
        log(level: .info, message: message)
    }
    
    func error(_ message: String) {
        log(level: .error, message: message)
    }
    
    private func log(level: LogLevel, message: String) {
        let formatted = formatter.format(level: level, message: message)
        output.write(formatted)
    }
}

let optimizedManager = LogManager(output: ConsoleOutput(), formatter: DefaultFormatter())
optimizedManager.info("App started") // 输出: [INFO] App started
  • 优化点:
    • 泛型替代协议类型,避免动态分派。
    • 依赖注入确保清晰性。

第四步:扩展与内存优化

添加文件输出,并优化内存管理:

struct FileOutput: LogOutput {
    private let fileURL: URL
    
    init(fileName: String) {
        let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
        fileURL = documents.appendingPathComponent(fileName)
    }
    
    func write(_ text: String) {
        if let data = "\(text)\n".data(using: .utf8) {
            try? data.appendToURL(fileURL)
        }
    }
}

// 扩展 Data 以追加到文件
extension Data {
    func appendToURL(_ url: URL) throws {
        if FileManager.default.fileExists(atPath: url.path) {
            let fileHandle = try FileHandle(forWritingTo: url)
            fileHandle.seekToEndOfFile()
            fileHandle.write(self)
            fileHandle.closeFile()
        } else {
            try write(to: url)
        }
    }
}

let fileManager = LogManager(output: FileOutput(fileName: "log.txt"), formatter: DefaultFormatter())
fileManager.error("File error") // 写入文件: [ERROR] File error
  • 内存优化:
    • 避免存在类型,直接使用具体类型。
    • 文件操作使用追加模式,减少内存占用。

第五步:性能优化

为高频调用添加内联提示:

protocol LogOutput {
    @inlinable func write(_ text: String)
}

extension LogOutput {
    @inlinable func write(_ text: String) {
        print(text) // 默认实现
    }
}
  • @inlinable 减少分派开销。
  • 适用场景:频繁调用的日志输出。

第六步:测试优化后的系统

添加单元测试验证功能和性能:

struct MockOutput: LogOutput {
    var logs: [String] = []
    mutating func write(_ text: String) {
        logs.append(text)
    }
}

struct MockFormatter: LogFormatter {
    func format(level: LogLevel, message: String) -> String {
        "\(level.rawValue): \(message)"
    }
}

import XCTest
class LogManagerTests: XCTestCase {
    func testLogging() {
        var output = MockOutput()
        let formatter = MockFormatter()
        let manager = LogManager(output: output, formatter: formatter)
        
        manager.info("Test info")
        manager.error("Test error")
        
        XCTAssertEqual(output.logs, ["INFO: Test info", "ERROR: Test error"])
    }
    
    func testPerformance() {
        let manager = LogManager(output: ConsoleOutput(), formatter: DefaultFormatter())
        measure {
            for _ in 0..<10000 {
                manager.info("Performance test")
            }
        }
    }
}
  • 测试点:
    • 功能:验证日志格式和输出。
    • 性能:使用 measure 检查优化效果。

案例分析

  1. 性能优化:
    • 泛型和内联减少了动态分派。
  2. 内存管理:
    • 无存在类型,文件追加避免大内存分配。
  3. 最佳实践:
    • 简洁协议、依赖注入和清晰文档。
  4. 扩展性:
    • 可轻松添加新输出(如网络)或格式化方式。

进一步优化建议

  • 异步支持:
    protocol AsyncLogOutput {
        func write(_ text: String) async
    }
    
    • 适用于高并发场景。
  • 缓存日志:
    • 批量写入文件,减少 I/O 开销。

注意事项

  • 权衡复杂度:优化需根据实际需求,避免过度设计。
  • 测试覆盖:确保所有路径经过验证。
  • 平台适配:文件路径需考虑跨平台兼容。

小结

通过优化一个协议化的日志系统,我们展示了性能提升、内存管理和最佳实践的综合应用。这一案例整合了第九章的核心内容,为开发者提供了可复用的优化模板。本书下一章将探讨协议化编程的未来趋势,展望其发展方向。


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