You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带关联类型的两个协议:如何以类型安全方式关联实现?

Swift中封装带关联类型的第三方网络框架实现类型安全抽象

核心方案是让自定义Resource协议承担类型映射的责任,通过添加关联类型和转换方法,将第三方框架的细节完全隐藏在协议实现内部,同时保证类型安全。

1. 修改自定义Resource协议,添加映射要求

在对外暴露的Resource协议中定义关联类型和转换方法,让每个具体的Resource实现类负责与第三方资源/模型的转换逻辑:

// 对外暴露的网络资源协议
protocol Resource {
    /// 自定义业务模型类型
    associatedtype Model
    /// 对应的第三方框架资源类型(仅内部可见,使用者无需关心)
    associatedtype ThirdPartyResourceType: ThirdPartyResource
    
    /// 将自定义资源转换为第三方框架资源
    func toThirdPartyResource() -> ThirdPartyResourceType
    /// 将第三方框架返回的模型转换为自定义业务模型
    static func convert(from thirdPartyModel: ThirdPartyResourceType.Model) -> Model
}

2. 实现MyAPI的fetch方法

在MyAPI的泛型fetch方法中,直接调用Resource协议定义的转换方法,无需直接依赖第三方框架的类型:

struct MyAPI {
    private let networkingClient: ThirdPartyNetworkingClient
    
    func fetch<R: Resource>(_ resource: R, completion: @escaping (Result<R.Model, Error>) -> Void) {
        // 1. 转换为第三方框架资源
        let thirdPartyResource = resource.toThirdPartyResource()
        
        // 2. 调用第三方框架的fetch方法
        networkingClient.fetch(thirdPartyResource) { result in
            switch result {
            case .success(let thirdPartyModel):
                // 3. 转换为自定义业务模型
                let customModel = R.convert(from: thirdPartyModel)
                completion(.success(customModel))
            case .failure(let error):
                completion(.failure(error))
            }
        }
    }
}

3. 具体Resource实现示例

以获取用户列表为例,实现自定义Resource并完成转换逻辑(第三方框架的类型仅在内部实现中出现,对外完全隐藏):

// 对外暴露的自定义业务模型
struct User {
    let id: Int
    let name: String
}

// 第三方框架模型(内部实现,不对外暴露)
private struct ThirdPartyUser {
    let user_id: Int
    let user_name: String
}

// 第三方框架资源(内部实现,不对外暴露)
private struct ThirdPartyUserListResource: ThirdPartyResource {
    typealias Model = [ThirdPartyUser]
    let query: String
}

// 自定义Resource实现(对外暴露)
struct UserListResource: Resource {
    typealias Model = [User]
    typealias ThirdPartyResourceType = ThirdPartyUserListResource
    
    func toThirdPartyResource() -> ThirdPartyUserListResource {
        ThirdPartyUserListResource(query: "/api/users")
    }
    
    static func convert(from thirdPartyModel: [ThirdPartyUser]) -> [User] {
        thirdPartyModel.map { User(id: $0.user_id, name: $0.user_name) }
    }
}

方案优势

  • 完全隐藏实现细节:第三方框架的ThirdPartyResource和模型类型仅在内部实现中出现,对外只暴露自定义的Resource和业务模型
  • 类型安全保障:编译器会严格检查转换逻辑的类型匹配,避免运行时错误
  • 扩展性良好:新增接口时只需实现Resource协议的两个方法,无需修改MyAPI的核心代码
  • 单一职责清晰:每个Resource实现类负责自身的转换逻辑,代码结构更清晰

内容的提问来源于stack exchange,提问作者Mischa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 23:54:41