iOS设计模式-适配器

思想

本质是 把一个"接口不兼容"的对象,转换成你当前系统期望的接口,从而进行调用。

------将一个类的接口,转换成客户端期望的接口,使原本不兼容的类可以协同工作。

------在两个不兼容的接口之间架一座"桥",让原本无法协作的类可以一起工作,而不必修改原有代码。

可以理解为"中间翻译层"。

总结来说,适配器模式用于解决接口不兼容的问题,通过适配器将不兼容的接口转换为兼容的接口,从而使得不同的类能够一起工作。

三个角色

适配者:具有原始接口的类

抽象接口:客户端期望的接口形式

适配器:封装,转发调用

应用场景

常用于集成/调用 第三方 SDK、适配旧代码、数据模型适配。

"旧代码 / 第三方库 / 不同结构的数据 → 统一成我当前代码能用的样子"

应用一: 第三方 SDK的二次封装

你接入了一个第三方 SDK,它的接口不符合你当前项目的设计规范(比如命名、回调方式不同)。即使规范,原则上也不要直接依赖,直接调用其接口。

swift 复制代码
class ThirdPartyAudioSDK { 
    // 播放
    func loadAndPlay(path: String, volume: Float) {
        print("SDK 播放: \(path) 音量: \(volume)") 
    } 
}
  • 一般调用方式,直接依赖SDK类
scss 复制代码
class VC { 
    func do(){
        let sdk = ThirdPartyAudioSDK()
        sdk.loadAndPlay()
    }
}

采用适配器模式,对SDK进行包装

1、设计抽象协议(接口)

swift 复制代码
protocol AudioPlayer { 
    func play(file: String) 
}

2、设计适配器类

遵循协议,持有SDK对象。实质:调用转发

swift 复制代码
class AudioPlayerAdapter: AudioPlayer {
    private let sdk = ThirdPartyAudioSDK()

    func play(file: String) {
        // 转换调用:适配接口差异
        sdk.loadAndPlay(path: "/media/\(file)", volume: 1.0)
    }
}

业务调用

php 复制代码
class VC {
    func playMusic(player: AudioPlayer) {
        player.play(file: "song.mp3")
    }
}

self.playMusic(player: AudioPlayerAdapter())

这样就实现了解耦,业务代码只依赖 AudioPlayer 协议,不知道内部用的是第三方 SDK。

好处:可灵活更换SDK;不污染业务代码。

应用二:服务器数据 的封装

服务端返回的JSON数据,最好不要直接读取使用。原因:

  • 避免耦合
  • 字段名不规范/适合
  • 不是所有字段都显示在UI上
  • 需要进行数据转换/预处理
json 复制代码
{
    "num": 1,
    "is_expire": 0,
    "reward_content": "10",
    "reward_name": "WSpoint_reward",
    "reward_type": 1,
    "sign_state": 3,
    "sign_time": 0,
    "trigger_type": 1
}

解析

rust 复制代码
struct UserDTO: Decodable {
    let sign_time: String
    let trigger_type: Int
    ....
}

采用适配器模式,对服务端返回的数据进行封装

1、设计抽象协议

涵盖 业务层需要用到的数据,及 UI层可直接展示的数据

如:

kotlin 复制代码
protocol UIDataDisplay { 
    var count: Int { get }
    var name: String { get }
    .....
}

2、设计适配器类

kotlin 复制代码
class ModelAdater: UIDataDisplay {
    let json: UserDTO
    
    var num: Int
    var type: Int
    ...

    init(json: UserDTO){
        self.num = json.num
        ...
    }
    
    // 实现抽象属性
    var count: Int {
        return json.num
    }
    
    var name: String { 
        return json.firstName + json.secondName
    }
}

3、UI 与 具体数据类型 解耦

swift 复制代码
class Cell {
    func config(model: UIDataDisplay){
        self.nameLabel.text = model.name
        ...
    }
}

好处

  • 数据集中在Adapter进行处理
  • 解耦 UI 和数据结构
  • 扩展性,后端字段变了 → 只改 Adapter
相关推荐
卸任6 小时前
Vibe coding工具使用心得
前端·ai编程
brien97 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance7 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M8 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写8 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李8 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易8 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马8 小时前
前沿视界
前端
kyriewen8 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
陈随易8 小时前
3000 万人在用的翻译插件,重写一遍就是一门生意
前端·后端·程序员