设计模式

创建型设计模式

创建型设计模式通常是五种。简单工厂模式是工厂模式的简化,使用频繁,所以单独拿出来。

模式名称 核心思想 典型应用场景 iOS示例 优缺点对比
单例 (Singleton) 确保类只有一个实例并提供全局访问点 全局配置、共享服务 [UIApplication sharedApplication][NSNotificationCenter defaultCenter] ✅ 节约资源
❌ 测试困难,可能隐藏依赖
工厂方法 (Factory Method) 定义创建对象的接口,让子类决定实例化哪个类 多平台UI组件创建 [NSNumber numberWith...]系列方法、UIFont+systemFontOfSize: ✅ 解耦调用方与具体类
❌ 每新增产品需新增工厂类
抽象工厂 (Abstract Factory) 创建相关或依赖对象的家族,而不需指定具体类 跨平台UI套件、主题系统 NSArray/NSMutableArrayalloc/init组合 ✅ 保证产品兼容性
❌ 扩展新产品族困难
建造者 (Builder) 分步骤创建复杂对象,相同构建过程可生成不同表示 复杂对象配置 UIAlertController配置、NSURLComponents ✅ 灵活构造对象
❌ 代码冗余,适合复杂对象
原型 (Prototype) 通过复制现有对象来创建新对象 对象创建成本高时 NSCopying协议(copy方法)、UIViewcopyWithZone: ✅ 避免重复初始化
❌ 深拷贝实现复杂

关键对比维度:

  1. 灵活性:建造者 > 工厂方法 > 单例
  2. 复杂度:抽象工厂 > 建造者 > 原型
  3. iOS集成度:单例 > 工厂方法 > 原型
  4. 适用场景
    • 简单全局访问 → 单例
    • 多态对象创建 → 工厂方法
    • 复杂参数配置 → 建造者

零.简单工厂模式

简单工厂模式提供了一个创建对象的接口,根据传入参数决定返回实例。

应用

比如苹果系统里:

[UIImage imageNamed:"icon"];
[UIImage imageWithContentsOfFile:path];

优点:将对象的创建使用分离,减低耦合。
缺点:新增产品类的时候,会改动工厂的创建细节,违反了开闭原则。

Apple使用的基本都是简单工厂模式,更简洁简单。

一.工厂方法模式

工厂方法模式将对象的实例化交给子类实现,通过父类方法调用,子类决定返回哪个对象。(抽象工厂类+多个具体工厂类+多个产品类)
比如苹果系统里的NSCoder,具体提供了NSKeyedArchiver以及NSArchiver等几种方式编码解码。
比如cellForRow,可以返回不同的Cell.
典型第三方应用:CTMediator
通过字符串+消息转发的方式,将vc的创建交给各自的模块,统一返回uiviewcontroller。体现工厂方法的核心精神:延迟决定具体类型,对客户隐藏创建细节,便于扩展。
(根据target找到对应的类,实例化对象,调用其action方法。每个模块都有自己的target类和action方法的具体实现。)
不完全是工厂模式的原因,没有使用传统的protocol定义接口,而是使用target+action的字符串映射方式。
实际应用:
比如点击一个按钮,可能根据逻辑的不同创建不同的子VC。子类封装详细的创建过程,决定返回哪个对象。而对外是统一的viewController。

OC强大的runtime,分类和block常用来解耦。所以更多的是简单工厂模式。纯粹的工厂方法模式需要额外的子类,优点重,开源库里并不多。

二.抽象工厂模式

创建一系列相关或者相互依赖对象的接口,无需指定具体的类。(满足开闭原则,对扩展开放,对修改关闭)
比如苹果系统里:
Apple提供了一个抽象的外功工厂机制,让我们可以根据不同环境统一创建,配置一整套控件外观。
抽象工厂:UIAppearance。
具体工厂:UITraitCollection
抽象产品: 遵循的控件
具体产品:UILabel,UIButton
核心:统一生产/配置一整套互相关联的UI样式对象。
通过UIAppearance的接口操作各个具体控件。

三.单例模式

确保一个类只有一个实例,并提供一个全局访问点。适用于全局唯一,统一管理,系统服务类。
苹果系统里:
全局状态共享:UserDefaults,UIApplication
系统统一管理:NotificationCenter,URLSession
资源复用,避免重复实例化:FileManager,AVAudioSession
优点:不用重复创建,任何地点访问。
缺点:滥用,内存升高,错误修改,可能耦合度高,测试困难。

由于存在经典问题:
优化一:依赖注入
将单例变为普通实例,需要的地方创建单例并通过依赖注意方式(指定满足某个协议,该单例实现了此协议)传入,然后在内部使用。

四.建造者模式

将复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
优点:分不构造复杂对象,更好的封装性
缺点:多个类,代码复杂
苹果系统:
UIAlertController的使用。
分步创建title,actions,最后present出去。
实际应用:
比如项目的各种配置,比如多段动画的组合。

原型模式

通过复制现有的对象来创建新对象,而不是通过传统的新建类实例的方式。在 iOS 开发中,原型模式主要通过 NSCopying 协议实现。
优点:避免复杂初始化过程,更高效。
缺点:需要注意深拷贝与浅拷贝。
实际使用:
比如富文本模式。可以创建一个消息模板,指定颜色字体等等。后续只需要copy再修改文字即可,避免初始化代价高。

结构型设计模式

模式名称 核心思想 典型应用场景 iOS示例 优缺点对比
适配器 (Adapter) 转换接口使不兼容的类可以协作 集成第三方库、旧系统改造 UITableViewDataSourceNSURLSessionAlamofire桥接 ✅ 解决接口兼容问题
❌ 过度使用会增加复杂度
桥接 (Bridge) 将抽象与实现分离,使它们可以独立变化 跨平台UI渲染、多数据库支持 UISwitch/UISlider的样式与逻辑分离、Core Graphics绘图API ✅ 提高扩展性
❌ 设计难度较高
组合 (Composite) 以树形结构组合对象,统一对待单个对象和组合对象 视图层级、菜单系统 UIViewaddSubview:UIStackView ✅ 简化客户端代码
❌ 类型检查可能变复杂
装饰器 (Decorator) 动态添加职责而不修改原类 扩展对象功能 Category扩展方法、CALayer视觉装饰 ✅ 比继承更灵活
❌ 多层装饰难调试
外观 (Facade) 为复杂子系统提供统一简化接口 SDK封装、复杂系统简化 AVFoundationAVPlayer封装底层音视频处理 ✅ 降低使用难度
❌ 可能限制灵活性
享元 (Flyweight) 共享细粒度对象以减少内存占用 频繁创建的对象池化 UITableViewCell重用机制、UIColor共享对象 ✅ 提升性能
❌ 需要区分内部/外部状态
代理 (Proxy) 为其他对象提供代理以控制访问 懒加载、访问控制 NSProxyUIScrollViewDelegate(部分特性) ✅ 增强安全性/功能
❌ 可能引入额外调用开销

关键对比维度:

  1. 接口转换能力:适配器 > 外观 > 代理
  2. 结构灵活性:组合 > 桥接 > 装饰器
  3. 性能优化:享元 > 代理 > 外观
  4. iOS集成度:装饰器(Category) > 代理(Delegate) > 组合(UIView)

使用建议:

  • 接口兼容Protocol+适配器类(适配器)
  • 多维度扩展Category+组合对象(装饰器)
  • 复杂系统封装 → 统一管理器类(外观)
  • 性能敏感场景 → 对象池/缓存(享元)

一.代理模式

代理模式是一种对象之间一对一通信方式,一个对象将某些事情的决策权、执行权交给另一个对象去完成。
优点:解耦,灵活,职责清晰。
典型的代表就是UITableViewDelegate,UITableViewDataSource

二.适配器模式

用于将一个类的接口转换成客户端期望的另一种接口,让原本不兼容的两个类可以协同工作。
比如:
对已有的老的不兼容的就旧接口做统一适配,包装成新接口,就是适配器模式。
典型:
不同平台登陆适配,不同平台支付适配。swift与OC代码桥接。
典型第三方应用:AFNetworking
AFNetworking中,AFURLSessionManager对NSURLSession的代理方法进行了适配,转换成了block的回调方式,并且统一管理task与回调的关联

典型适配器,把代理适配成了block
原接口:NSURLSession代理方法(delegate)
目标接口:block回调形式

三.外观模式

为复杂子系统提供一个统一的、高层的对外接口,让外部代码不需要直接依赖子系统的复杂实现,达到简化调用、解耦依赖的目的。
(简单说:为复杂的内部系统提供一个门面)
系统应用:
UIApplication就是系统的门面,包含时间分发,状态窗口管理等等。
实际应用:
将项目作为SDK提供给客户使用时,统一提供Interface类供客户使用。简化使用,隐藏内部复杂细节,是典型的外观模式。

AFNetworking中使用NSURLSessionManager对NSURLSession的封装体现了适配器设计模式的使用。而使用AFHTTPSessionManager统一封装了请求,序列化,错误处理等子系统,提供了简化统一的对外接口,则体现了外观模式的设计模式。

四.桥接模式

将抽象部分与实现部分分离,是他们可以独立变化,通过桥接类再它们之间建立连接。方便替换。
系统应用:
UIView和CAlayer。
UIView是抽象层,负责响应,布局,事件等。CALayer是实现层,负责绘制,动画等。
UIView内部组合CALayer,形成灵活的桥接结构。
举例:

CAShapeLayer *shapeLayer = [CAShapeLayer layer];
//对shapeLayer进行各种操作
...
...
UIView *customView = [[UIView alloc] initWithFrame:frame];
[customView.layer addSublayer:shapeLayer];

view和layer独立实现,灵活组合。
典型第三方应用:AFNetworking
AFNetworkging的抽象层是AFURLSessionManager,供上层使用。具体的实现层是NSURLSession。通过delegate和block的方式桥接二者。
典型第三方应用:SDWebimage

// 运行时注册不同解码器
[[SDImageCodersManager sharedManager] addCoder:[SDWebImageJPEGCoder new]];

// 注册使用不同的imageloader
SDWebImageManager.sharedManager.loaders = @[
    [SDImageCache sharedCache],
    [MyCustomLoader new],
    [SDWebImageDownloader sharedDownloader]
];

五.组合模式

将对象组合成树形结构以表示“部分-整体”的层次结构,使客户端对单个对象和对象集合的使用具有一致性。
(将单个对象和组合对象统一对待)
系统应用:
UIView的视图层级系统。UIView既可以是单个对象(比如一个UILabel),也可以是对象集合(比如嵌套多层的根view),都统一对外提供addSubview,removeFromSuperview等接口。
优点:清晰表达了部分-整体结构。无需区分单个对象和组合对象,统一操作
缺点:结构嵌套多不易维护
典型第三方应用:Masonary
Masonary把每个MASConstraint统一放到MASConstraintMaker中,统一使用make处理。

六.享元模式

共享相同对象,减少内存使用,提高性能。核心思想是把对象分为内部状态和外部状态,内部状态共享不变(存在共享池),在外部环境中变化的部分,由外部传入(使用的具体内容,场景等)。
系统应用:
UIFont就是典型的享元模式。多个地方使用相同的字体,系统只保留一份UIFont对象,避免重复开销。
比如使用UIFont.systemFont(ofSize:14),系统会先查找字体缓存池,如果有则直接返回,如果没有则创建新的并加入。
tableviewCell的重用也是享元模式的一种具体应用。
典型第三方应用:SDWebimage
SDWebimage中的SDImageCache就是一个享元对象池,合理复用相同的图片资源,提升性能。

七.装饰器模式

在不改变原有对象结构的前提下,通过装饰器动态包装,动态地为其增加额外的功能。
系统应用:
UIControl通过状态调整外观,有些类似装饰器模式。但这些状态管理机制是通过配置,合肥包装,所以有区别。
典型第三方应用:CocoaLumberjack
设置不同的日志目标来装饰日志记录行为:

//控制台输出日志
[DDLog addLogger:[DDTTYLogger sharedInstance]];
//文件输出日志
[DDLog addLogger:[[DDFileLogger alloc] init]];
//设置日志级别
[DDTTYLogger sharedInstance].logFormatter = [[CustomLogFormatter alloc] init];

CocoaLumberjack在设计时大量使用了装饰器模式,尤其在日志目标和日志级管理上。
日志目标作为装饰器:通过组合多个日志目标,动态添加日志输出目标,不改变记录日志核心内容
日志级别控制:日志级别的装饰,可以根据配置过滤日志,控制哪些日志被记录,进一步增强了装饰器模式的灵活性。

行为型设计模式

总结对比表

模式名称 核心思想 典型应用场景 iOS示例 优缺点对比
责任链 (Chain of Responsibility) 多个对象依次处理请求,直到有对象处理它为止 事件传递、审批流程 UIResponder链(nextResponder)、NSURLProtocol拦截 ✅ 降低耦合度
❌ 请求可能未被处理
命令 (Command) 将请求封装为对象,支持参数化、队列化和日志化 撤销/重做、远程控制 NSInvocationUIButtonaddTarget:action: ✅ 解耦调用者和执行者
❌ 可能产生大量命令类
解释器 (Interpreter) 定义语法规则并解释语言中的句子 正则表达式、DSL语言 NSPredicateNSExpression ✅ 易于扩展语法
❌ 复杂语法难以维护
迭代器 (Iterator) 提供顺序访问聚合对象元素的方法 集合遍历 NSEnumerator、快速枚举(for...in ✅ 统一遍历接口
❌ 某些语言已内置支持
中介者 (Mediator) 通过中介对象封装一组对象的交互 复杂UI组件通信 UIDataSourceModelAssociation、自定义协调器 ✅ 减少对象间依赖
❌ 中介类可能变得复杂
备忘录 (Memento) 捕获并外部化对象状态以便后续恢复 撤销操作、状态持久化 NSKeyedArchiverUIStateRestoring ✅ 状态保存/恢复简单
❌ 可能消耗内存
观察者 (Observer) 对象间定义一对多依赖,状态变化时自动通知 数据绑定、事件通知 KVONSNotificationCenterCombine框架 ✅ 实时响应变化
❌ 需注意注销观察者
状态 (State) 允许对象在内部状态改变时改变行为 订单状态机、UI控件状态 UIViewisHidden/isUserInteractionEnabledUIControl状态 ✅ 简化条件分支
❌ 状态多时代码量增加
策略 (Strategy) 定义算法族并使其可互换 排序算法、布局策略 NSSortDescriptorUICollectionViewLayout ✅ 灵活切换算法
❌ 客户端需了解策略差异
模板方法 (Template Method) 在父类定义算法骨架,子类重写特定步骤 生命周期钩子、流程标准化 UIViewController生命周期方法、NSOperationmain方法 ✅ 代码复用
❌ 可能违反开闭原则
访问者 (Visitor) 将操作与对象结构分离,可在不修改类的情况下新增操作 复杂数据结构操作 NSFileManager的目录遍历、自定义AST处理 ✅ 集中相关操作
❌ 增加新元素类困难

关键对比维度:

  1. 解耦程度:观察者 > 中介者 > 命令
  2. 扩展性:访问者 > 策略 > 状态
  3. iOS集成度:观察者(KVO) > 模板方法(生命周期) > 责任链(Responder Chain)
  4. 复杂度:访问者 > 解释器 > 中介者

使用建议:

  • 简单事件通知NSNotificationCenter(观察者)
  • 算法切换NSSortDescriptor(策略)
  • UI状态管理UIControlState(状态)
  • 撤销操作NSUndoManager(命令+备忘录)

一.观察者模式

一种一对多的依赖关系。让多个观察者对象同时监听某一个主题对象。当主题对象发生改变时,它会自动通知所有依赖于它的观察者对象,使它们能够及时更新。
系统应用:
NotificationCenter 通知中心
KVO
优点:解耦,灵活,多对多。
缺点:通知链复杂,不易维护
典型第三方应用:ReactiveObjC
ReactiveObjC就是用信号+订阅者的方式实现了观察者模式。它同时做了链式、响应式、异步流的封装,写起来更优雅灵活。

二.访问者模式

在不改变数据结构的前提下,给一组对象增加新的操作。通过定义访问者,封装对一组元素对象的操作,把数据结构和操作解耦。
比如:公园中有草地,花坛,长椅等元素。不同的访问者执行不同的操作。清洁工打扫草地,园艺师修剪花坛,检察员检查长椅。
系统应用:
遍历view树,为其中的每一个控件(UIButton,UILabel)等加边框,或者检查状态,进行统计等。
典型第三方应用:SDWebImage
其中的清理内存操作用到了访问者思想,但由于缓存只有磁盘和内存两种,并没有设计具体的visiter。

//遍历所有缓存文件
//判断缓存文件最后的修改日期是否过期
//如果过期则删除

虽然访问者模式本身是个比较结构话的设计模式,但很多优秀第三方库在对象遍历+操作解耦产经,都在用类似访问者模式的思想,只是不完全一样。

三.中介者模式

用于减少对象之间直接交互,避免多个对象直接互相引用,减少它们之间的依赖。中介者模式通过一个中介对象来协调对象间的交互,从而降低它们的耦合度。
系统应用:NotificationCenter
传统面向对象中对象间直接互相调用,紧耦合。而NotificationCenter提供了一种松耦合机制,允许对象间通过NotificationCenter这个中介者进行发布通知和接受通知,无需直接联系。
典型第三方应用:CocoaLumberjack
DDlog作为中介者,接受来自不同组件的信息。这些组件之间不直接进行通信。

四.命令模式

将请求封装成对象,从而使你可以用不同的请求、队列、日志来参数化其他对象,并支持撤销、重做、事务等操作。
系统应用:
UIButton的Target-Action就是典型的命令模式。
Button(invoker)触发事件,调用对应的action(command),执行到target(receiver)。
(命令模式的简化,如果扩展为命令对象+历史记录,就能支持撤销,重做,完美实现完整的命令模式)
典型第三方应用:AFNetworking
AFHTTPRequestOperationManager内部维护一个operationQueue为调用者
AFURLConnectionOperation为命令,实现了start及cancel的处理
NSURLSessionTask为具体的接收者
典型第三方应用:SDWebImage
SDWebImageDownloader维护队列是invoker
SDWebImageDownloadOperation是命令对象,封装了开始(start),取消(cancel)等逻辑
NSURLSession

命令模式等于把请求封装成命令对象,调用者执行命令,接收者处理具体逻辑。解耦调用者和接收者,便于拓展、撤销、重做等。

五.状态模式

润许一个对象在内部状态改变时,行为也改变,就像变成另一个对象一样。
系统应用:
UIButton的Normal,Highlighted,Disabled,Selected。不同的状态显示的文字图片颜色等都不一样。是状态模式的一种应用。
典型第三方应用:MJRefresh
根据当前不同的状态(空闲,下拉,刷新,没有更多数据),显示不同的UI,执行不同的逻辑。

状态模式通过封装状态、分离行为,让对象在内部状态变化时,自动切换行为,避免了复杂的条件分支,让代码更优雅。iOS中的UI控件状态、任务状态、播放器状态等都用到了这种设计模式。

六.策略模式

定义一系列算法,封装起来,并且使它们可以相互替换。
系统应用:
NSURLSesssion的请求缓存策略。配置不同的策略,在发起请求时根据不同的策略执行不同的缓存规则。
UIViewContentMode。根据多种不同的策略,决定子视图内容如何在父视图中进行排布和缩放。
典型第三方应用:SDWebimage
SDWebimage的缓存策略。
SDWebiamge的解码策略。
SDWebimage的setimage策略。注意这不是严格意义上的策略模式,而是策略配置。使用枚举+分支的判断方式,控制不同策略路径。但没有抽象出统一策略接口+多个独立策略类。

iOS系统中大量使用了策略模式,通过定义统一策略接口(枚举、协议、Block)+多个具体实现策略+context环境类,达成运行时可自由切换、行为解耦、扩展灵活的优雅设计。

七.解释器模式

主要是将语言中的句子转化为能够被计算机理解的格式。
系统应用:
正则表达式
NSPredicate(谓词)

八.迭代器模式

为一个集合(数组、列表、集合)提供一种顺序访问其元素的方法,而不暴露内部表示。通过迭代器模式,客户端可以以统一的方式遍历集合元素,且不需要关心集合内部的具体实现。
系统应用:NSArray
NSArray的enumerateObjectsUsingBlock方法,就是允许我们使用迭代器的方式来遍历数组。
同样可以使用迭代器来遍历缓存。

九. 备忘录模式

允许在不暴露对象内部结构的情况夏,保存和恢复对象的状态。
系统应用:UItextView
在文本编辑应用中,每次用户编辑文本时,程序会保存当前的文本状态,并允许用户在需要时恢复到先前的状态。
典型第三方应用:Realm

十. 模板方法

父类定义好模板方法,规定好步骤顺序,子类通过重写某些方法,来改变某些细节步骤。
系统应用:UITableview
整个UITableView的流程时苹果写好的,而我们可以定制它流程中的某些步骤。
典型第三方应用:AFNetworking
父类模板:AFURLSessionManager类封装了NSURLSession的网络请求管理,定义了表组合你的网络请求-相应处理流程。包括:创建task->监听task回调->解析响应->处理错误->执行完成回调。
子类重写:比如服务器给我们数据加密,我们可以在URLSession: task: didCompleteWithError中先进行手动解密,再走后续解析(task.completionHandler()),流程顺序不变,细节改变。
子类重写:比如自定义下载进度上报方式。我们可以在URLSession:dataTask:didReceiveData中重写,每5%回调一次。

十一.责任链模式

将多个处理者串联成一条链,请求从链起点对象发出,依次沿着链传递,直到有一个对象处理它为止。
系统应用:UIResponder事件响应链
iOS中的UIResponder链,比如触摸事件touchesBegan:withEvent:就是典型的责任链模式。如果当前视图不处理,事件就会沿着nextResponder传递,直到有对象处理。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 对象创建-Object Creation 1.原型 -Prototype 定义原型模式是一种简单的设计模式,客户端...
    陵无山阅读 9,164评论 0 7
  • 设计模式概述 在学习面向对象七大设计原则时需要注意以下几点:a) 高内聚、低耦合和单一职能的“冲突”实际上,这两者...
    彦帧阅读 9,165评论 0 14
  • 第一部分 设计模式与设计原则 设计模式概述 创建型模式(Creational Patterns) 工厂模式(Fac...
    Aurora_NeAr阅读 775评论 0 1
  • 学习《设计模式之美》笔记。 23 种经典设计模式共分为 3 种类型,分别是创建型、结构型和行为型 创建型模式 创建...
    lconcise阅读 5,855评论 0 3
  • 结构型设计模式汇总 结构型设计模式名称 结构型设计模式主要包括 7 大类: 代理模式 桥接模式 装饰器模式 适配器...
    allen218阅读 3,505评论 0 0