适配器模式

定义 适配器模式(Adapter Pattern)是一种结构型设计模式,它将一个类的接口转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作。 适配器模式的核心思想是:通过一个中间层(适配器)来使不兼容的接口能够一起工作,而无需修改原有代码。 为什么需要适配器模式 适配器模式要解决的核心问题是:让接口不兼容的类能够一起工作,而不需要修改原有代码。 问题场景:假设我们的App原来使用的是自己封装的网络库,现在想要切换到Alamofire,但项目中有大量地方直接使用了旧接口。 // 旧的网络接口 - 项目中到处都在使用 protocol OldNetworkClient { func get(url: String, callback: @escaping (Data?, Error?) -> Void) func post(url: String, body: Data?, callback: @escaping (Data?, Error?) -> Void) } // 新引入的Alamofire有完全不同的接口 // AF.request(url).response { response in ... } 最直接的方式是修改所有调用处: // 需要修改项目中所有使用旧接口的地方 // 从: oldClient.get(url: "https://api.example.com/users") { data, error in ... } // 改为: AF.request("https://api.example.com/users").response { response in ... } 这种方式有什么问题? 工作量巨大:需要修改项目中所有使用网络请求的地方 风险高:大量修改容易引入bug 难以回退:如果新库有问题,很难切换回旧实现 违反开闭原则:修改了大量现有代码 适配器模式的解决思路: 创建一个适配器,让新库"伪装"成旧接口,现有代码无需修改: // 适配器 - 让Alamofire适配旧接口 class AlamofireAdapter: OldNetworkClient { func get(url: String, callback: @escaping (Data?, Error?) -> Void) { // 内部使用Alamofire,但对外暴露旧接口 AF.request(url).response { response in callback(response.data, response.error) } } func post(url: String, body: Data?, callback: @escaping (Data?, Error?) -> Void) { AF.request(url, method: .post, parameters: nil, encoding: URLEncoding.default) .response { response in callback(response.data, response.error) } } } // 现有代码完全不需要修改 let client: OldNetworkClient = AlamofireAdapter() client.get(url: "https://api.example.com/users") { data, error in // 原有的处理逻辑保持不变 } 适配器模式的好处: ...

June 21, 2026

设计模式概述

什么是设计模式? 设计模式(Design Pattern)是软件开发中反复出现问题的经典解决方案。它们是前人在大量实践中总结出的、被证明有效的代码设计经验,可以帮助开发者编写出更加灵活、可维护、可复用的代码。 设计模式不是具体的代码,而是解决特定问题的思想和模板。正确运用设计模式可以: 提高代码的可读性和可维护性 增强代码的可复用性 降低模块间的耦合度 提供通用的设计词汇,便于团队沟通 设计模式的起源 设计模式的概念最早由"四人帮"(Gang of Four,简称GoF)在1994年出版的《Design Patterns: Elements of Reusable Object-Oriented Software》一书中系统化提出。书中总结了23种经典设计模式,这些模式至今仍是软件设计的重要参考。 设计模式分类 GoF将23种设计模式分为三大类: 创建型模式(Creational Patterns) 创建型模式关注对象的创建机制,旨在以合适的方式创建对象,而不是直接使用new操作符。这类模式使得代码在创建对象时更加灵活。 模式 描述 iOS常见应用 单例模式 确保一个类只有一个实例 UIApplication.shared、FileManager.default 工厂方法模式 定义创建对象的接口,由子类决定实例化哪个类 NSNumber的工厂方法 抽象工厂模式 创建一系列相关对象而无需指定具体类 UIKit组件创建 建造者模式 将复杂对象的构建与表示分离 URLComponents、AlertController 原型模式 通过复制现有实例创建新对象 NSCopying协议 结构型模式(Structural Patterns) 结构型模式关注类和对象的组合,用于形成更大的结构。这类模式帮助确保当系统的一部分发生改变时,整个系统不需要随之改变。 模式 描述 iOS常见应用 适配器模式 将一个类的接口转换成客户期望的另一个接口 协议适配、第三方库封装 桥接模式 将抽象部分与实现部分分离 平台无关的抽象设计 组合模式 将对象组合成树形结构以表示部分-整体层次结构 UIView层级结构 装饰器模式 通过包装对象在运行时动态添加职责 包装器对象、链式装饰 外观模式 为子系统提供一个统一的高层接口 SDK封装、模块门面 享元模式 运用共享技术有效支持大量细粒度对象 字体对象、颜色对象等可共享的不可变对象 代理模式 为其他对象提供一种代理以控制访问 NSProxy、虚拟代理、保护代理 行为型模式(Behavioral Patterns) 行为型模式关注对象之间的通信和职责分配,描述类或对象如何交互以及如何分配职责。 ...

May 27, 2026

责任链模式

定义 责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它将请求的发送者和接收者解耦,让多个对象都有机会处理请求。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。 责任链模式的核心思想是:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象组成一条链,并沿着这条链传递请求,直到有对象处理它为止。 为什么需要责任链模式 问题场景:假设我们正在开发一个审批系统,不同金额的报销需要不同级别的人员审批。 最直接的方式可能是这样: class ExpenseApproval { func approve(amount: Double) { if amount <= 1000 { // 组长审批 teamLeaderApprove(amount) } else if amount <= 5000 { // 部门经理审批 departmentManagerApprove(amount) } else if amount <= 10000 { // 总监审批 directorApprove(amount) } else { // CEO审批 ceoApprove(amount) } } func teamLeaderApprove(_ amount: Double) { ... } func departmentManagerApprove(_ amount: Double) { ... } func directorApprove(_ amount: Double) { ... } func ceoApprove(_ amount: Double) { ... } } 这种方式有什么问题? ...

May 2, 2026

观察者模式

定义 观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一对多依赖关系,当一个对象(主题/被观察者)的状态发生改变时,所有依赖于它的对象(观察者)都会收到通知并自动更新。 观察者模式也被称为发布-订阅模式(Publish-Subscribe Pattern)。 为什么需要观察者模式 观察者模式要解决的核心问题是:当一个对象的状态发生变化时,如何自动通知所有依赖它的对象。 问题场景:假设我们正在开发一个电商App,用户登录后需要更新多个页面的状态(首页显示用户名、购物车同步、个人中心更新等)。 最直接的方式可能是这样: class LoginService { func login(username: String, password: String) { // 登录成功后... let user = User(name: username) // 直接调用各个需要更新的对象 HomeViewController.shared.updateUser(user) CartViewController.shared.syncCart(for: user) ProfileViewController.shared.refreshProfile(user) // 如果还有其他需要通知的地方,继续添加... } } 这种方式有什么问题? 紧耦合:LoginService必须知道所有需要通知的对象,依赖关系错综复杂 难以维护:每新增一个需要监听登录事件的页面,都要修改LoginService 违反开闭原则:对扩展不开放,每次扩展都要修改已有代码 单例滥用:为了让LoginService能访问到各个页面,不得不使用大量单例 观察者模式的解决思路: 被观察者(Subject)只负责"广播"状态变化,不关心谁在监听;观察者(Observer)自己注册感兴趣的事件: // 使用NotificationCenter实现 class LoginService { func login(username: String, password: String) { let user = User(name: username) // 只负责发送通知,不关心谁在监听 NotificationCenter.default.post( name: .userDidLogin, object: nil, userInfo: ["user": user] ) } } // 各个页面自己注册监听 class HomeViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver( self, selector: #selector(handleUserLogin), name: .userDidLogin, object: nil ) } @objc func handleUserLogin(_ notification: Notification) { if let user = notification.userInfo?["user"] as? User { updateUI(with: user) } } } 观察者模式的好处: ...

May 2, 2026

装饰器模式

定义 装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许向现有对象动态添加新功能,同时又不改变其结构。装饰器通过创建一个包装对象来包裹真实对象,实现在不修改原有对象的基础上扩展功能。 装饰器模式的核心思想是:使用组合而非继承来扩展对象的功能,遵循"对扩展开放,对修改关闭"的原则。 为什么需要装饰器模式 装饰器模式要解决的核心问题是:在不修改原有对象的情况下,动态地给对象添加新功能。 问题场景 假设我们正在开发一个UI组件库,需要为UILabel添加各种视觉效果:圆角、阴影、边框、渐变背景等。而且这些效果需要能够自由组合。 方案一:使用继承(不推荐) // 基础标签 class BasicLabel: UILabel { init(text: String) { super.init(frame: .zero) self.text = text } } // 圆角标签 class RoundedLabel: BasicLabel { override init(text: String) { super.init(text: text) layer.cornerRadius = 8 clipsToBounds = true } } // 阴影标签 class ShadowLabel: BasicLabel { override init(text: String) { super.init(text: text) layer.shadowColor = UIColor.black.cgColor layer.shadowOffset = CGSize(width: 0, height: 2) layer.shadowOpacity = 0.3 } } // 边框标签 class BorderLabel: BasicLabel { override init(text: String) { super.init(text: text) layer.borderWidth = 1 layer.borderColor = UIColor.gray.cgColor } } // 如果需要圆角+阴影呢? class RoundedShadowLabel: BasicLabel { override init(text: String) { super.init(text: text) // 重复圆角代码 layer.cornerRadius = 8 clipsToBounds = true // 重复阴影代码 layer.shadowColor = UIColor.black.cgColor layer.shadowOffset = CGSize(width: 0, height: 2) layer.shadowOpacity = 0.3 } } // 如果需要圆角+边框呢? class RoundedBorderLabel: BasicLabel { /* 又要重复代码 */ } // 如果需要阴影+边框呢? class ShadowBorderLabel: BasicLabel { /* 继续重复代码 */ } // 如果需要圆角+阴影+边框呢? class RoundedShadowBorderLabel: BasicLabel { /* 所有代码都重复一遍 */ } 这种方式的问题: ...

May 2, 2026

策略模式

定义 策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。策略模式让算法独立于使用它的调用者而变化。 策略模式的核心思想是:将算法的定义与使用分离,通过组合而非继承来实现算法的切换。 为什么需要策略模式 在实际开发中,我们经常会遇到这样的场景:同一个功能有多种实现方式,而且这些实现方式需要根据不同条件进行切换。 问题场景:假设我们正在开发一个电商App的支付功能,需要支持信用卡、Apple Pay、支付宝等多种支付方式。 最直接的实现方式可能是这样: func processPayment(type: String, amount: Double) { if type == "creditCard" { // 信用卡支付逻辑(可能有几十行代码) print("Processing credit card payment...") } else if type == "applePay" { // Apple Pay支付逻辑 print("Processing Apple Pay...") } else if type == "alipay" { // 支付宝支付逻辑 print("Processing Alipay...") } // 后续可能还要添加更多支付方式... } 这种实现方式存在几个明显的问题: 违反开闭原则:每次添加新的支付方式,都需要修改这个函数,增加新的分支 代码臃肿:随着支付方式增多,函数会变得越来越长,难以维护 测试困难:所有支付逻辑耦合在一起,难以单独测试某种支付方式 复用性差:如果其他地方也需要使用某种支付逻辑,只能复制代码 策略模式的解决思路: 策略模式将每种支付方式抽取为独立的类(策略),它们都实现相同的接口。调用方只需要持有策略接口的引用,不需要知道具体是哪种实现。 这样做的好处是: 新增支付方式:只需要新建一个策略类,无需修改现有代码 代码清晰:每种支付逻辑独立封装,职责单一 易于测试:可以对每种策略单独进行单元测试 运行时切换:用户可以随时切换支付方式,系统只需要替换策略对象 简单来说,策略模式就是把「做什么」和「怎么做」分离开来——调用方只关心「做什么」,具体「怎么做」由不同的策略类来决定。 模式结构 classDiagram class Context { -strategy: Strategy +setStrategy(strategy: Strategy) +executeStrategy() } class Strategy { <<interface>> +execute() } class ConcreteStrategyA { +execute() } class ConcreteStrategyB { +execute() } class ConcreteStrategyC { +execute() } Context o-- Strategy Strategy <|.. ConcreteStrategyA Strategy <|.. ConcreteStrategyB Strategy <|.. ConcreteStrategyC 角色说明 Strategy(策略接口):定义所有支持的算法的公共接口 ConcreteStrategy(具体策略):实现Strategy接口的具体算法 Context(上下文):持有Strategy的引用,负责调用策略方法 iOS中的实现 基础实现 // 策略协议 protocol PaymentStrategy { func pay(amount: Double) -> Bool var name: String { get } } // 具体策略 - 信用卡支付 class CreditCardPayment: PaymentStrategy { private let cardNumber: String private let cvv: String var name: String { "Credit Card" } init(cardNumber: String, cvv: String) { self.cardNumber = cardNumber self.cvv = cvv } func pay(amount: Double) -> Bool { print("Paying \(amount) using Credit Card ending with \(cardNumber.suffix(4))") // 实际支付逻辑 return true } } // 具体策略 - Apple Pay class ApplePayPayment: PaymentStrategy { var name: String { "Apple Pay" } func pay(amount: Double) -> Bool { print("Paying \(amount) using Apple Pay") // 调用Apple Pay SDK return true } } // 上下文 class PaymentContext { private var strategy: PaymentStrategy init(strategy: PaymentStrategy) { self.strategy = strategy } func setStrategy(_ strategy: PaymentStrategy) { self.strategy = strategy } func checkout(amount: Double) -> Bool { print("Processing payment with \(strategy.name)...") return strategy.pay(amount: amount) } } // 使用 let creditCard = CreditCardPayment(cardNumber: "1234567890123456", cvv: "123") let context = PaymentContext(strategy: creditCard) context.checkout(amount: 99.99) // 切换支付方式 let applePay = ApplePayPayment() context.setStrategy(applePay) context.checkout(amount: 99.99) 使用闭包简化策略 对于简单的策略,可以使用闭包代替完整的类: ...

May 2, 2026

生产者消费者模式

定义 生产者消费者模式(Producer-Consumer Pattern)是一种并发设计模式,它通过一个共享的缓冲区来解耦生产者和消费者,使得生产者和消费者可以以不同的速度工作,而不需要直接相互依赖。 生产者负责产生数据并放入缓冲区,消费者从缓冲区中取出数据进行处理。这种模式是多线程编程中最经典的设计模式之一。 为什么需要生产者消费者模式 生产者消费者模式要解决的核心问题是:如何在生产者和消费者处理速度不一致的情况下,实现高效、安全的数据传递。 问题场景:假设我们正在开发一个图片处理App,用户选择多张图片后需要进行滤镜处理。图片加载速度快,但滤镜处理速度慢。 最直接的方式可能是这样: class ImageProcessor { func processImages(_ urls: [URL]) { for url in urls { // 加载图片(快) let image = loadImage(from: url) // 应用滤镜(慢) let filtered = applyFilter(to: image) // 保存结果 saveImage(filtered) } } private func loadImage(from url: URL) -> UIImage { /* ... */ } private func applyFilter(to image: UIImage) -> UIImage { /* ... */ } private func saveImage(_ image: UIImage) { /* ... */ } } 这种方式有什么问题? ...

May 2, 2026

建造者模式

定义 建造者模式(Builder Pattern)是一种创建型设计模式,它将复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。建造者模式特别适用于创建包含多个可选参数的对象。 建造者模式的核心思想是:将一个复杂对象的构建过程分解为多个简单的步骤,通过一步一步地构建,最终得到完整的对象。 为什么需要建造者模式 建造者模式要解决的核心问题是:简化复杂对象的创建过程,特别是当对象有很多可选参数时。 问题场景:假设我们需要创建一个网络请求配置对象,它有很多可选参数。 使用构造函数的方式: struct NetworkConfig { let baseURL: URL let timeout: TimeInterval let retryCount: Int let cachePolicy: CachePolicy let headers: [String: String] let enableLogging: Bool let certificatePinning: Bool // 构造函数参数太多! init(baseURL: URL, timeout: TimeInterval = 30, retryCount: Int = 3, cachePolicy: CachePolicy = .default, headers: [String: String] = [:], enableLogging: Bool = false, certificatePinning: Bool = false) { // ... } } // 使用时 - 参数太多,难以阅读 let config = NetworkConfig( baseURL: URL(string: "https://api.example.com")!, timeout: 60, retryCount: 5, cachePolicy: .reloadIgnoringCache, headers: ["Authorization": "Bearer token"], enableLogging: true, certificatePinning: true ) 这种方式有什么问题? ...

May 2, 2026

工厂模式

定义 工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种创建对象的方式,将对象的创建逻辑与使用逻辑分离。工厂模式有三种变体:简单工厂模式、工厂方法模式和抽象工厂模式。 为什么需要工厂模式 工厂模式要解决的核心问题是:将对象的创建过程与使用过程分离。 问题场景:假设我们正在开发一个网络层,需要创建URLSession对象。 直接使用构造函数创建对象看起来很简单: class NetworkManager { func fetchData(from url: URL) { // 直接创建URLSession let config = URLSessionConfiguration.default config.timeoutIntervalForRequest = 30 config.httpAdditionalHeaders = ["Authorization": "Bearer xxx"] let session = URLSession(configuration: config) session.dataTask(with: url) { data, response, error in // 处理响应... }.resume() } } 这种方式有什么问题? 创建逻辑与业务逻辑混在一起:fetchData方法既要负责创建session,又要负责发起请求,职责不单一 创建逻辑无法复用:如果另一个方法也需要相同配置的session,只能复制这段创建代码 难以替换实现:如果想在测试时使用Mock的session,或者在不同环境使用不同配置,需要修改业务代码 隐藏了依赖关系:从方法签名看不出这个类依赖URLSession,依赖关系被隐藏在方法内部 工厂模式的解决思路: 工厂模式的核心是:调用方不再自己new对象,而是向工厂"要"对象。 // 工厂负责创建 class URLSessionFactory { static func createDefault() -> URLSession { let config = URLSessionConfiguration.default config.timeoutIntervalForRequest = 30 config.httpAdditionalHeaders = ["Authorization": "Bearer xxx"] return URLSession(configuration: config) } static func createBackground(identifier: String) -> URLSession { let config = URLSessionConfiguration.background(withIdentifier: identifier) return URLSession(configuration: config) } } // 业务代码只负责使用 class NetworkManager { private let session: URLSession init(session: URLSession = URLSessionFactory.createDefault()) { self.session = session } func fetchData(from url: URL) { session.dataTask(with: url) { data, response, error in // 处理响应... }.resume() } } 这样做的好处: ...

May 2, 2026

外观模式

定义 外观模式(Facade Pattern)是一种结构型设计模式,它为子系统中的一组接口提供一个统一的高层接口。外观模式定义了一个高层接口,使得子系统更加容易使用。 外观模式的核心思想是通过引入一个外观类,将复杂子系统的内部复杂性隐藏起来,只暴露一个简单的接口给客户端。 为什么需要外观模式 外观模式要解决的核心问题是:简化复杂子系统的使用,为客户端提供一个更简单的接口。 问题场景:假设我们正在开发一个视频播放功能,需要处理音频、视频、字幕等多个子系统。 直接使用各个子系统: class VideoPlayerController { func playVideo(url: URL) { // 1. 初始化音频引擎 let audioEngine = AudioEngine() audioEngine.configure(sampleRate: 44100) audioEngine.setOutputDevice(.speaker) // 2. 初始化视频解码器 let videoDecoder = VideoDecoder() videoDecoder.setCodec(.h264) videoDecoder.configureHardwareAcceleration(true) // 3. 初始化渲染器 let renderer = VideoRenderer() renderer.setResolution(1920, 1080) renderer.setFrameRate(30) // 4. 加载字幕 let subtitleLoader = SubtitleLoader() let subtitles = subtitleLoader.load(from: url) // 5. 同步各个组件 let synchronizer = AVSynchronizer() synchronizer.link(audio: audioEngine, video: videoDecoder) // 6. 开始播放 let data = loadVideoData(url) let decodedVideo = videoDecoder.decode(data) renderer.render(decodedVideo) audioEngine.play() // 还要处理暂停、seek、音量调节... } } 这种方式有什么问题? ...

May 2, 2026