设计模式:
备注:消息传递模型(Message Passing)是Objective-C语言的核心机制。在Objective-C中,没有方法调用这种说法,只有消息传递。在C++或Java中调用某个类的方法,在Objective-C中是给该类发送一个消息。在C++或Java里,类与类的行为方法之间的关系非常紧密,一个方法必定属于一个类,且于编译时就已经绑定在一起,所以你不可能调用一个类里没有的方法。而在Objective-C中就比较简单了,类和消息之间是松耦合的,方法调用只是向某个类发送一个消息,该类可以在运行时再确定怎么处理接受到的消息。也就是说,一个类不保证一定会响应接收到的消息,如果收到了一个无法处理的消息,那么程序就是简单报一个错。甚至你可以向一个值为nil的空对象发送消息,系统都不会出错或宕掉。这种设计本身也比较符合软件的隐喻。
原型模式:
只要复制自身要比手工实例化对象要好,都可以使用原型对象。此模式的最低限度是生成对象的真实副本(即深度复制)。
Cocoa Touch框架为NSOBject的派生类提供了实现深度复制的协议。NSObject的子类需要实现NSCopying协议及其方法:-(id)copyWithZone:(NSZone *)zone。 NSObject有一个实例方法叫做(id)copy。 默认的copy方法调用[self copyWithZone:nil] 。对于采纳了NSCopying协议得子类,需要实现这个方法。
工厂方法:
工厂方法适用情形:
1, 编译时无法预期要创建的对象的类
2, 类想让其子类决定在运行时创建什么
3, 类有若干子类,而你想将返回哪个子类这一信息局部化。
使用这一模式的常见例子是ccoca touch框架中的NSNumber。
NSNumber可以将基本数据类型包装起来,形成一个对象,这样就可以给其发送消息,装入NSArray中等等。
NSNumber * intNumber=[NSNumber numberWithInt:100];
NSNumber *floatNumber=[NSNUmber numberWithFloat:100.00];
int i=[intNumber intValue];
if([intNumber isEqualToNumber:floatNumber]) ....
NSNumber继承NSObject ,可以使用比较 compare: isEqual等消息
numberWithX是工厂方法。
抽象工厂:
抽象工厂常见于cocoa touch框架。有很多基础类采用这一模式。NSNumber就是一个抽象工厂。
生成器模式:
生成器模式把过程分为客户—指导者—生成器(client-director-buider)的关系。
何时使用生成器模式:
1. 需要创建涉及各种部件的复杂对象
2. 创建过程需要一不同方式构建对象
例子:创建游戏中的角色。ChasingGame(指导者) CharacterBuilder(基类 生成器)
stardCharacterBuilder(子类生成器) character(角色类)
单例模式:
这一模式的意图是使得类的一个对象成为系统中唯一的实例。
使用单例模式的情况:
1. 类只能有一个实例,而且必须从一个为人熟知的访问点对其进行访问,比如工厂方法。
2. 这个唯一的实例只能通过子类化对其进行扩展,且扩展的对象不会破坏客户端代码
框架中极为常见的一个单例类是UIApplicaton类。每一个应用程序有且仅有一个UIApplication的实例。他由UIApplicationMain函数在应用程序启动时创建为单例对象。之后,对同一UIApplication实例可以通过其sharedApplication类方法进行访问。
还有UIAccelermeter类和NSFileManager类也是单例类。
适配器模式:
适配器也称包装器(wrapper)。适配器模式用于连接两种不同种类的对象,使其毫无问题地协同工作。
基本上有两种实现适配器的方式。第一种是通过继承来适配两个接口。这种称为类适配器。
如obj-c中的继承并实现协议。
还有一种方式称为对象适配器,与类适配不同,对象适配不继承被适配者,而是组合了一个对他的引用。
适配器模式适用情形:
1. 已有类的接口与需求不匹配。
2. 想要一个可复用的类
3. 需要适配一个类的几个子类
Obj-c中的委托就是对适配器模式的运用
桥接模式:
桥接模式的目的是把抽象层次结构从具体实现中分离。见(p105)
外观模式:
外观模式位子系统中的一组不同接口提供统一接口。为子系统的接口提供简化的接口。
外观模式的适用情形:
1. 子系统正变得复杂。子系统用起来较困难。
2. 可以使用外观对子系统进行分层。 (p115)
中介者模式:
中介者模式用于定义一个集中地场所,对象间的交互可以在一个中介者对象中处理。其他对象不必彼此交互,因此减少了他们的依存关系。
何时使用中介者模式:
1. 对象间的交互虽定义明确然而非常复杂,导致对象彼此相互依赖难以理解
2. 因为对象引用许多其他对象并与其通讯,导致对象难以复用。
3. 想要定制一个分布在多了类中的逻辑或行为,又不想生成太多子类
如ios项目中涉及很多的试图迁移,可以创建一个专门的类来管理这些迁移,这个类就是个中介者。
观察者:
观察者模式又称发布—订阅模式。观察者(订阅杂志的人)通过通知器(杂志发行商)把自己注册到(订阅)特定的通知(杂志)。当有通知的时候,观察者只通过通知器得到他订阅的通知。
观察者模式适用情形:
1. 有两种抽象类型相互依赖。将他们封装在各自的对象中,就可以对他们进行单独改变和复用。
2. 对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变
3. 一个对象必须通知其他对象,而他又不知道其他对象是什么。
Cocoa touch框架用两种技术改写了观察者模式。通知和健值观察。(具体见p139)
组合模式:
组合模式可以让我们把相同基类型的对象组合到树状结构中。其中的父节点包含同类型的子节点。
组合模式适用情形:
1. 想获得对象的抽象的树形表示
2. 想让客户端同一处理组合结构中的所有对象
在cocoa touch框架中,UIView被组织成一个组合结构。每一个UIView实例可以包含UView的其他实例,形成统一的树形结构。
迭代器模式:
迭代器提供了一种顺序访问聚合(集合)对象中元素的方法,而无需暴露结构的底层表示和细节。
迭代器模式适用情形:
1. 需要访问组合对象中的内容
2. 需要通过多种方式遍历组合对象
3. 需要提供一个统一接口,用来遍历各种类型的组合对象
苹果公司用枚举器/枚举改写了迭代器模式。基础框架中的类NSEnmerator类实现了迭代器模式。抽象的NSEnmerator类的私有具体子类返回枚举器对象。能够顺序遍历各种组合,数组,set,字典。
访问者模式:
访问者模式可以用日常生活中的例子描述。例如管道工来你家修管子。管道工就是访问者。你开门让他进来(接受访问),然后他进来修管子(访问)。访问者模式的构造方法见(p181)
访问者模式适用情形:
1. 一个复杂的对象结构包含很多其他对象,他们有不同的接口,但是想对这些对象实施一些依赖与其他具体类型的操作。
2. 需要对一个组合结构中的对象进行很多不想关的操作,但是不想让这些操作污染这些对象的类。
3. 定义结构复杂的类很少做修改,但经常需要向其添加新的操作
访问者模式的功效类似于obj-c里的category很象。访问者模式是扩展组合结构的一种强大的方式。
装饰模式:
装饰模式的目的是向对象添加行为,而不破坏其原有风格,因此增强的对象是同一个累的加强版。可以使用子类或category来实现模式。装饰模式类图见(p191)
装饰模式的使用情形:
1. 想要在不影响其他对象的情况下,以动态,透明的方式给单个对象添加职责。
2. 想要扩展一个类的行为,却做不到。
3. 对类的职责的扩展是可选的
责任链模式:
责任链模式的主要思想是,对象引用了同一类型的对象,形成了一条链,链中每个对象实现了同样的方法,处理对链中第一个对象发起的同一请求。如果一个对象不知道如何处理请求,他就把请求传给下一个响应器(successor)
责任链适用情形:
1. 有多个对象可以处理请求,而处理程序只有在运行时才能确定
2. 向一组对象发出请求,而不想显示指定处理请求的特定程序。
RPG游戏中的防御系统就可以用责任链模式
模板方法模式:
模板方法定义一个操作中算法的骨架,而将一些步骤延迟到子类中。
模板方法的适用情形:
1. 需要一次性实现算法的可变部分,并将可变的行为留给子类来实现
2. 子类的共同行为被提取到公共类中,一避免代码重复。
3. 需要控制子类的扩展。
在框架设计中,模板方法非常常见。模板方法是代码复用的基本技术。Cocoa touch中的模板方法有UIView中的-(void)drawRect(CGRect) rect
rotatingHeaderView等方法(p229)
策略模式:
面向对象的设计中,我们可以把算法分离为不同的类,称为策略。策略模式中一个关键角色是策略类它为所有支持的相关算法声明了一个共同接口。另外,还有使用策略接口来实现相关算法的具体策略类。
何时使用策略模式:
1. 一个类在其操作中使用多个条件语句来定义许多行为。
2. 需要算法的各种变体
3. 需要避免把复杂的,与算法相关的数据结构暴露给客户端(见p230)
命令模式:
面向对象设计中,我们借用了类似思想,把指令封装在各种命令对象中。命令对象可以被传递并且在指定的时刻被不同的客户端复用(p241)
何时使用命令模式:
1. 想让应用程序支持撤销与恢复
2. 想要在不同时刻对请求执行指定,排列和操作
3. 想要记录修改日志。
NSInvocationa NSUndoManager和“目标动作”机制是cocoa touch框架中对这个模式的典型应用。
享元模式:
在面向对象软件设计中,利用公共对象不仅能节省资源还能提高性能。比方说,某个任务需要一个类的一百万个实例,但我们可以把这个类的实例让大家共享,而把某些独特的信息放在外部,节省资源。实现享元模式需要两个关键组件。通常是可共享的享元对象和保存他们的共享池。
何时使用享元模式:
1. 应用程序使用很多对象
2. 在内存中保存对象会影响内存性能
百花池例子很好地演示了享元模式(p262)
代理模式:
利用代理模式,把操作推迟给代理对象处理来提升性能并提供对象访问。
有以下几种代理模式。
远程代理,虚拟代理,保护代理,智能引用代理。
何时使用代理模式:
1. 需要一个远程代理,为位于不同的地址空间或网络中的对象提供本地代表。
2. 需要一个虚拟代理,来根据要求创建重型的对象
3. 需要以一个保护代理,来根据不同访问权限控制对原对象的访问
4. 需要一个智能引用代理通过对实体对象的引用进行计数来管理内存。
ios应用中代理模式的一个常见例子是邮件应用(p278)
无论在何种ios设备中总是推荐lazy loading。 Lazy loading就是利用代理模式实现
备忘录模式:
在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以恢复这个对象的状态。这个模式有三个关键角色:原发器(originator),备忘录(mementor)和看管人。其思想很简单。原发器创建一个包含其状态的备忘录,并传给看管人,看管人不知如何与备忘录进行交互,但会把备忘录放在安全之处保管好。
何时使用备忘录模式:
1. 需要保存一个对象在某个时刻的状态
2. 用于获取状态的接口会暴露实现细节,需要将其隐藏起来
Cocoa Touch框架在归档,属性列表序列化和核心数据中才用了备忘录模式。