代理模式

在iOS开发中,“代理"这个词通常有两层含义: 设计模式中的代理模式(Proxy Pattern):提供目标对象的替代品或占位符,控制对目标对象的访问 iOS中的代理模式(Delegate Pattern):一种基于协议的回调机制,用于对象间通信 虽然中文都叫"代理”,但它们是不同的设计模式,解决不同的问题。本文将两者都进行详细介绍。 一、Proxy Pattern(代理模式) 定义 代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。 核心思想:代理对象作为真实对象的"替身",客户端通过代理间接访问真实对象。代理可以在访问前后添加额外逻辑,而调用者对此毫不知情。 Client → Proxy → RealSubject ↑ 控制访问 添加功能 延迟创建 关键特征: 代理对象与真实对象实现相同的接口 客户端不知道自己使用的是代理还是真实对象 代理对象持有真实对象的引用(通常是强引用) 模式结构 classDiagram class Subject { <<interface>> +request() } class RealSubject { +request() } class Proxy { -realSubject: RealSubject +request() } class Client { +useSubject() } Subject <|.. RealSubject Subject <|.. Proxy Proxy --> RealSubject : delegates to Client --> Subject : uses Proxy的类型 1. 虚拟代理(Virtual Proxy) 虚拟代理用于延迟创建开销大的对象,只有在真正需要时才创建: ...

May 2, 2026

单例模式

定义 单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例。 单例模式的核心要点: 唯一性:整个应用程序生命周期内只存在一个实例 全局访问:提供一个全局访问点获取该实例 懒加载:通常在第一次使用时才创建实例 为什么需要单例模式 单例模式要解决的核心问题是:确保某个类在整个应用中只有一个实例,并提供全局访问点。 问题场景:假设我们正在开发一个App,需要管理用户的登录状态和用户信息。 如果不使用单例,可能会遇到这样的问题: class UserManager { var currentUser: User? var isLoggedIn: Bool = false func login(user: User) { currentUser = user isLoggedIn = true } } // 在登录页面 let userManager1 = UserManager() userManager1.login(user: user) // 在个人中心页面 let userManager2 = UserManager() print(userManager2.isLoggedIn) // false!因为是不同的实例 这种方式有什么问题? 状态不一致:不同地方创建的UserManager是不同的实例,它们的状态相互独立,导致登录状态无法共享 资源浪费:如果UserManager管理的是数据库连接、网络会话等资源,创建多个实例会浪费系统资源 数据同步困难:多个实例之间的数据需要手动同步,容易出错 单例模式的解决思路: 单例模式确保整个应用只有一个UserManager实例,所有地方都访问同一个对象: class UserManager { static let shared = UserManager() private init() {} var currentUser: User? var isLoggedIn: Bool = false func login(user: User) { currentUser = user isLoggedIn = true } } // 在登录页面 UserManager.shared.login(user: user) // 在个人中心页面 print(UserManager.shared.isLoggedIn) // true!同一个实例 适合使用单例的场景: ...

May 2, 2026

命令模式

定义 命令模式(Command Pattern)是一种行为型设计模式,它将请求封装成对象,从而可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。 命令模式的核心思想是:将"请求"封装成一个对象,使得可以用不同的请求、队列或日志来参数化其他对象,同时支持可撤销操作。 为什么需要命令模式 命令模式要解决的核心问题是:将请求(操作)封装成对象,使得可以对请求进行存储、传递、撤销等操作。 问题场景:假设我们正在开发一个文本编辑器,需要支持撤销/重做功能。 最直接的方式可能是这样: class TextEditor { var text: String = "" func insertText(_ newText: String, at position: Int) { let index = text.index(text.startIndex, offsetBy: position) text.insert(contentsOf: newText, at: index) } func deleteText(from start: Int, length: Int) { let startIndex = text.index(text.startIndex, offsetBy: start) let endIndex = text.index(startIndex, offsetBy: length) text.removeSubrange(startIndex..<endIndex) } } // 用户操作 let editor = TextEditor() editor.insertText("Hello", at: 0) editor.insertText(" World", at: 5) editor.deleteText(from: 5, length: 6) // 如何实现撤销?需要记住每次操作的类型、参数、以及如何逆向执行 // 这变得非常复杂... 这种方式有什么问题? ...

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

工厂模式

定义 工厂模式(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

建造者模式

定义 建造者模式(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

生产者消费者模式

定义 生产者消费者模式(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

策略模式

定义 策略模式(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

装饰器模式

定义 装饰器模式(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

观察者模式

定义 观察者模式(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