设计模式概述

什么是设计模式? 设计模式(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

适配器模式

定义 适配器模式(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