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

第7章:协议在跨平台开发中的应用

7.2 跨平台业务逻辑的协议化实现

在跨平台开发中,业务逻辑是应用的核心部分,通常需要在多个平台上保持一致。通过协议化编程(POP),我们可以将业务逻辑抽象为与平台无关的接口,并通过协议定义依赖关系,从而实现跨平台的复用和解耦。本节将探讨如何使用协议设计和实现跨平台的业务逻辑,分析其实现步骤,并通过示例展示其实际应用。

为什么需要协议化业务逻辑?

业务逻辑(如用户认证、数据处理)通常是平台无关的,但其依赖的服务(如网络、存储)因平台而异。直接将业务逻辑与平台实现耦合会导致重复代码和维护困难。协议化方法通过以下方式解决问题:

  • 抽象依赖:将业务逻辑与平台特定服务分离。
  • 统一接口:为跨平台逻辑提供一致的调用方式。
  • 复用性:一套逻辑代码适配多个平台。

设计跨平台业务逻辑的步骤

  1. 定义业务协议:
    • 提取业务逻辑的核心行为,设计通用接口。
  2. 抽象依赖服务:
    • 使用协议定义业务逻辑所需的外部服务。
  3. 实现平台特定依赖:
    • 为每个平台提供具体实现。
  4. 注入依赖:
    • 通过依赖注入将平台实现传入业务逻辑。

示例:用户认证系统

假设我们要实现一个跨平台的用户认证系统,支持登录和用户信息获取。

第一步:定义业务协议
protocol AuthenticationService {
    func login(username: String, password: String) -> Bool
    func getUserInfo() -> User?
}

struct User {
    let id: String
    let name: String
}
  • AuthenticationService 定义了认证业务的核心功能。
第二步:抽象依赖服务

业务逻辑依赖网络和存储服务,用协议抽象:

protocol NetworkClient {
    func request(endpoint: String, parameters: [String: String]) -> Data?
}

protocol UserStore {
    func saveUser(id: String, name: String)
    func loadUser() -> User?
}
第三步:实现跨平台业务逻辑

创建一个业务模块,通过协议依赖外部服务:

class AuthManager: AuthenticationService {
    private let network: NetworkClient
    private let store: UserStore
    
    init(network: NetworkClient, store: UserStore) {
        self.network = network
        self.store = store
    }
    
    func login(username: String, password: String) -> Bool {
        let params = ["username": username, "password": password]
        if let data = network.request(endpoint: "/login", parameters: params) {
            let user = parseUser(from: data)
            if let user = user {
                store.saveUser(id: user.id, name: user.name)
                return true
            }
        }
        return false
    }
    
    func getUserInfo() -> User? {
        return store.loadUser()
    }
    
    private func parseUser(from data: Data) -> User? {
        // 模拟解析,实际应使用 JSONDecoder
        return User(id: "u001", name: "TestUser")
    }
}
  • AuthManager 是跨平台业务逻辑,只依赖协议接口。
第四步:实现平台特定依赖

为 iOS 和模拟环境提供实现:

struct iOSNetworkClient: NetworkClient {
    func request(endpoint: String, parameters: [String: String]) -> Data? {
        // 模拟 iOS 网络请求
        print("iOS request to \(endpoint) with \(parameters)")
        return "mock data".data(using: .utf8)
    }
}

struct iOSUserStore: UserStore {
    func saveUser(id: String, name: String) {
        UserDefaults.standard.set(name, forKey: "user_\(id)")
    }
    
    func loadUser() -> User? {
        if let name = UserDefaults.standard.string(forKey: "user_u001") {
            return User(id: "u001", name: name)
        }
        return nil
    }
}

struct MockNetworkClient: NetworkClient {
    func request(endpoint: String, parameters: [String: String]) -> Data? {
        return "mock data".data(using: .utf8)
    }
}

struct MockUserStore: UserStore {
    private var user: User?
    
    mutating func saveUser(id: String, name: String) {
        user = User(id: id, name: name)
    }
    
    func loadUser() -> User? {
        return user
    }
}
  • iOSNetworkClient 和 iOSUserStore 为 iOS 提供实现。
  • MockNetworkClient 和 MockUserStore 用于测试或模拟。
使用业务逻辑
let iOSAuth = AuthManager(network: iOSNetworkClient(), store: iOSUserStore())
let success = iOSAuth.login(username: "alice", password: "123")
print("Login \(success ? "succeeded" : "failed")") // 输出: Login succeeded
if let user = iOSAuth.getUserInfo() {
    print("User: \(user.name)") // 输出: User: TestUser
}
  • 业务逻辑无需修改即可适配不同平台。

测试跨平台逻辑

为 AuthManager 添加单元测试:

import XCTest
class AuthManagerTests: XCTestCase {
    func testLoginSuccess() {
        var mockStore = MockUserStore()
        let auth = AuthManager(network: MockNetworkClient(), store: mockStore)
        
        let success = auth.login(username: "bob", password: "456")
        XCTAssertTrue(success)
        XCTAssertEqual(auth.getUserInfo()?.name, "TestUser")
    }
    
    func testLoginFailure() {
        struct FailingNetwork: NetworkClient {
            func request(endpoint: String, parameters: [String: String]) -> Data? { nil }
        }
        var mockStore = MockUserStore()
        let auth = AuthManager(network: FailingNetwork(), store: mockStore)
        
        let success = auth.login(username: "bob", password: "456")
        XCTAssertFalse(success)
        XCTAssertNil(auth.getUserInfo())
    }
}
  • 测试验证了成功和失败路径,隔离了平台依赖。

跨平台实现的优势

  1. 复用性:
    • AuthManager 的逻辑跨平台共享,只需替换依赖实现。
  2. 解耦性:
    • 业务逻辑不依赖具体网络或存储,易于维护。
  3. 测试性:
    • Mock 对象模拟依赖,测试无需真实平台环境。
  4. 一致性:
    • 协议确保所有平台实现行为一致。

扩展到其他平台

为 Android 添加实现(假设 Swift 可跨平台编译):

struct AndroidNetworkClient: NetworkClient {
    func request(endpoint: String, parameters: [String: String]) -> Data? {
        print("Android request to \(endpoint)")
        return "android data".data(using: .utf8)
    }
}

struct AndroidUserStore: UserStore {
    func saveUser(id: String, name: String) {
        print("Android save: \(id) - \(name)")
    }
    
    func loadUser() -> User? {
        return User(id: "u001", name: "AndroidUser")
    }
}

let androidAuth = AuthManager(network: AndroidNetworkClient(), store: AndroidUserStore())
androidAuth.login(username: "charlie", password: "789")
  • 只需提供 Android 实现,业务逻辑保持不变。

注意事项

  • 协议设计:保持接口通用,避免平台特定假设。
  • 条件编译:使用 #if os() 区分平台实现。
  • 性能:动态分派可能影响性能,可优化为静态调用。

小结

通过协议化实现跨平台业务逻辑,我们将核心逻辑与平台依赖分离,实现了代码复用和解耦。本案例展示了设计和测试的全过程,为跨平台开发提供了实用模板。下一节将探讨协议在 UI 层跨平台中的应用,进一步扩展其用途。


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