iOS设计模式解析一书总结
在iOS中有21种设计模式,这些设计模式都是为了解决某种场景下的问题,可以把这21种设计模式分为如下场景下的几类:
- 对象创建
- 接口适配
- 对象去耦
- 抽象集合
- 行为扩展
- 算法封装
- 性能与对象访问
- 对象状态
对象创建
原型模式
- 什么是原型模式?
无需手动创建,就可以获得同一个类的多个实例。在iOS中,就是通过某个对象的copy方法,获得相同类型的实例。 - 在什么情况下会用原型模式?
- 需要创建的对象应独立于类型与创建方式(创建的时候不关心对象的创建方式及其类型
- 不同的实例间差异很小,只需要做一点点修改就可以,那么直接复制已有的类会更加方便
- 实例的创建过程很复杂,可能有多个对象的嵌套,那么直接复制会更加容易
- 如何使用原型模式?
使用copy方法
[obj copy]
不同于cocoa touch框架中的对象,如果是自定义的对象,那么需要继承NSCopying协议,并实现其中的
- (id)copyWithZone:(NSZone *)zone;
- 使用场景举例
画板功能中,有撤销和恢复的功能,此时需要记录每一个时刻的用户操作后的数据。以提供撤销和恢复的功能。要么就需要在用户一个绘画动作完成后,记录当前画板上所需要展示的模型,并copy一份压入撤销栈,下次用户操作时,改变的是当前界面展示的模型,想要撤销到上一次时,展示的又是copy后的那一份模型
工厂模式
- 什么是工厂模式?
- 各种子类对象重载其父类的构造方法,创建自己
- 抽象类提供不同的创建方法创建私有子类或者其他类的对象
- 什么情况下会使用工厂模式
- 编译时无法预估要创建什么类
- 抽象类想要其各个子类实现初始化方法
- 如何使用工厂模式
- 通过在抽象类中定义实例方法,在其子类中各自实现。并通过不同子类所对应的工厂调用构造方法来实现, 达到使用者-->工厂-->实例对象这一过程,这样做就降低了使用者与具体类的耦合,专注于工厂的构建就可以了。
- 类工厂方法 例如cocoaTouch中,NSNumber 的类工厂方法,其通过
[NSNumber numberWithBool:bool]
[NSNumber numberWithInt:int]
来创建一个合适的子类
抽象工厂
-
什么是抽象工厂?
通俗的来说,抽象工厂就是利用一个抽象类,使用工厂模式生产出子类工厂,子类工厂中,各自实现抽象工厂中的生产方法。 -
什么情况下会使用抽象工厂
有一些拥有共同的抽象特点但又有不同具体特点的产品,他们需要出自于不同的生产者。 -
如何使用抽象工厂
抽象工厂通常和工厂模式一起使用。在工厂模式,抽象工厂生产具体工厂,而具体工厂,负责抽象工厂中生产产品的实现,举例说明:
NSNumber *intNumber = [NSNumber numberWithInt:1];
NSNumber *boolNumber = [NSNumber numberWithBool:YES];
这里的NSNumber就是抽象的工厂,这两个方法,都是生产子工厂的方法。
[intNumber charValue];
[boolNumber charValue];
而这两个charValue方法,他们的实现分别来自于两种不同的子类,就是对NSNumber抽象工厂中的charValue方法的重载。charValue就是生产方法,其返回的char类型的值,就是生产出的产品
- 使用场景举例
在IM项目中,有朋友圈和聊天功能,在这两个功能有都有视频播放功能,而这两个场景下的视频播放界面可能是有区别的,假设两种场景下的播放、暂停按钮、或者其他用户操作按钮的UI不同,那么就可以抽象一个类,其提供返回工厂的方法和生产产品的方法,工厂方法来返回提供朋友圈和聊天中这些UI的工厂。生产产品的方法就是返回按钮、视图等。
生成器
-
什么是生成器模式?
生成器模式中,有两个重要的角色,一个是Director(指导者),一个是builder(生成者);Director知道builder应该建造什么,而builder知道该如何建造。在这个设计模式中,创建对象的核心思想是:
1、创建什么对象
2、如何创建对象
将这两部分分离则是重点 -
什么情况下会使用生成器模式?
个人理解:当构建的对象的条件很复杂,有一套规则/算法时,这套规则/算法对应的就是 “如何”,将“如何”分离出来。试想一下,如果一个对象的创建需要10个参数,并且这个对象的某些属性,还依赖于这10个参数来进行计算。那么,你是不是需要:
1、将不同对象的创建封装
2、将计算过程封装 -
疑问点
生成器模式的重点在于将 “什么”和“如何”分离,那么“什么”必须要是确定的,也就是对于应用层来说,创建什么是已知的,如果是未知,那么创建对象所需要的条件一旦可变动,客户端就必须知道这些条件。这种情况下,生成器模式就不适用了。 -
使用场景举例
vip模块中,不同vip的权限是不同的,不同vip对应的权限是已定的。如果不适用生成器模式,那么代码可能会是这样
if (type == vip1) {
xxxxEnable = YES;
...
} else if (type == vip2) {
xxxxEnable = YES;
...
} else if (type == vip3) {
xxxxEnable = YES;
...
}
return vip;
生成器模式中,代码会是这样的
vip1 = [director createVip1:builder];
vip2 = [director createVip2:builder];