第一章,你好,设计模式
图书相关的一些资源
http://www.ocdesignpatterns.com/
源代码下载地址 www.apress.com
设计模式是为特定场景下的问题而定制的解决方案。
针对接口编程,而不是针对实现编程
接口定义了类型。类继承与借口继承的关系
类继承是通过复用父类的功能,来定义对象新的实现的一种机制。
使用接口的好处:
只要对象符合客户端所要求的接口,客户端就不必在意所使用对象的确切类型。
客户端只知道定义接口的协议或者抽象类,因此客户端对对象的类一无所知。
第3章 原型模式 Prototype
原型模式:使用原型实例指定创建对象的种类,并通过复制这个原型创建新的对象。
第4章 工厂模式
对调用的类来说,只需要知道事物的基类和工厂的实现类就可以,
返回的是抽象类。
抽象工厂
CanvasViewGenerator.h
#import "CanvasView.h"
@interface CanvasViewGenerator :NSObject
- (CanvasVIew *)canvasViewWithFrame:(CGRect)aFrame;
@end
CanvasViewGenerator.m
#import "CanvasViewGenerator.h"
@implement CanvasViewGenerator
- (CanvasView *)canvasViewWithFrame:(CGRect)aFrame{
return [[CanvasView alloc]initWithFrame:aFrame];
}
@end
抽象实体
实现工厂
PaperCanvasViewGenerator.h
#import "CanvasViewGenerator.h"
#import "PaperCanvasView.h"
@interface PaperCanvasViewGenerator :CanvasViewGenerator
- (CanvasVIew *)canvasViewWithFrame:(CGRect)aFrame;
@end
PaperCanvasViewGenerator.m
#import "PaperCanvasViewGenerator.h"
@implement PaperCanvasViewGenerator
- (CanvasView *)canvasViewWithFrame:(CGRect)aFrame{
return [[CanvasView alloc]initWithFrame:aFrame];
}
ClothCanvasViewGenerator.h
#import "ClothCanvasViewGenerator.h"
#import "ClothCanvasView.h"
@interface ClothCanvasViewGenerator :CanvasViewGenerator
- (CanvasVIew *)canvasViewWithFrame:(CGRect)aFrame;
@end
ClothCanvasViewGenerator.m
#import "ClothCanvasViewGenerator.h"
@implement ClothCanvasViewGenerator
- (CanvasView *)canvasViewWithFrame:(CGRect)aFrame{
return [[ClothCanvasView alloc]initWithFrame:aFrame];
}
实现实体
#import <UIKit/UIKit.h>
#import "CanvasView.h"
#import "PaperCanvasView.h"
@interface PaperCanvasView:CanvasView
//私有变量
//私有方法
- (instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
UIImage *backgroundImage = [UIImage imageNamed:@"paper"];
UIImageView *backgroundView = [[UIImageView alloc]initWithImage:backgroundImage];
[self addSubview:backgroundView];
}
return self;
}
@end
#import <UIKit/UIKit.h>
#import "CanvasView.h"
#import "ClothCanvasView.h"
@interface ClothCanvasView:CanvasView
//私有变量
//私有方法
- (instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
UIImage *backgroundImage = [UIImage imageNamed:@"cloth"];
UIImageView *backgroundView = [[UIImageView alloc]initWithImage:backgroundImage];
[self addSubview:backgroundView];
}
return self;
}
@end
//客户端调用工厂方法,客户端和具体的实现是解耦的,
//如果后续需要增加一种新的画布,客户端不需要修改已经有的代码,只需要在需要调用的地方添加即可
- (void)viewDidLoad{
CanvasViewGenerator *defaultGenerator = [[ClothCanvasViewGenerator alloc]init];
CanvasView *aCanvasView = [self loadCanvasViewWithGenerator:defaultGenerator];
}
- (void)loadCanvasViewWithGenerator:(CanvasViewGenerator *)generator{
[canvasView_ removeFromSuperView];
CGRect aFrame = CGRectMake(0,0,320,436);
CanvasView *aCanvasView = [generator canvasViewWithFrame:aFrame];
[self setCanvasView:aCanvasView];
[self.view addSubview:aCanvasView];
}
第5章 抽象工厂
抽象工厂:提供一个创建一系列相关或互相依赖对象的接口,而无需指定他们具体的类。
简单工厂,工厂方法,抽象工厂方法的区别
http://www.cnblogs.com/zhangchenliang/p/3700820.html
第6章 生成器
生成器:将一个复杂对象的构建和表现分离,相同的构建可以创建不同的表现。
第7章 单例
第三部分 接口适配
第8章 适配器
适配器模式:将一个类的接口转换为客户希望的另外一个接口,适配器模式使得由于接口不兼容而不能一起工作的那些类可以一起工作。
应用场景,
已有类接口与需求不匹配,
想要一个复用的类,该类能够与不兼容的其他类写作,
用块语法实现适配器
第9章 桥接
桥接模式:将抽象部分与实现部分分类,使他们都可以独立地变化
使用场景
抽象和实现都可以通过子类化独立进行扩展
对抽象的实现进行修改不应影响客户端代码
如果每个实现需要额外的子类以细化抽象,则说明有必要把他们分成2个部分
想在带有不同抽象接口的多个对象之间共享一个实现。
第10章 外观
外观:为系统中的一组接口提供一个统一的接口,外观定义了一个高层接口,让子系统更易于使用。
汽车类,负责 启动,加油等操作
#import <Foundation/Foundation.h>
@interface Car : NSObject
{
}
// ...
- (void) releaseBrakes;
- (void) changeGears;
- (void) pressAccelerator;
- (void) pressBrakes;
- (void) releaseAccelerator;
// ...
@end
#import "Car.h"
@implementation Car
- (void) releaseBrakes
{
}
- (void) changeGears
{
}
- (void) pressAccelerator
{
}
- (void) pressBrakes
{
}
- (void) releaseAccelerator
{
}
计价器,负责计算价格
#import <Foundation/Foundation.h>
@interface Taximeter : NSObject
{
}
- (void) start;
- (void) stop;
@end
#import "Taximeter.h"
@implementation Taximeter
- (void) start
{
}
- (void) stop
{
}
@end
司机类,负责开车和计价,但是给客户端调用的时候提供了唯一的方法 - (void) driveToLocation:(CGPoint) x;方便客户端调用
#import "Taximeter.h"
@implementation Taximeter
- (void) start
{
}
- (void) stop
{
}
@end
#import "CabDriver.h"
@implementation CabDriver
- (void) driveToLocation:(CGPoint) x
{
// ...
// set off the taximeter
Taximeter *meter = [[Taximeter alloc] init];
[meter start];
// operate the vehicle
// until location x is reached
Car *car = [[Car alloc] init];
[car releaseBrakes];
[car changeGears];
[car pressAccelerator];
// ...
// when it's reached location x
// then stop the car and taximeter
[car releaseAccelerator];
[car pressBrakes];
[meter stop];
// ...
}
@end
调用代码
CabDriver *cab = [[CabDriver alloc]init];
[cab driveToLocation:CGPointMake(100, 100)];
第11章 中介者
中介者模式,用一个对象来封装一系列对象的交互方式。中介者使各对象不需要互相饮用,从而使其耦合松散,而且可以独立地改变他们之间的交互。
使用场景:对象之间的交互虽然定义明确然而非常复杂,导致一组对象彼此互相依赖
因为对象引用了许多其他对象并与其通讯,导致对象难以复用
想要定制一个分部在多个类的逻辑或行为,又不想生成太多子类
第12章 观察者
观察者模式:定义对象见的一种一对多的依赖关系,当一个对象的状态发生改变时,依赖于他的对象都得到通知并被自动更新。
使用场景:
有2种抽象类型互相依赖,将它们封装在各自的对象中,就可以对它们单独进行改变和复用
对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变
一个对象必须通知其他对象,而它又不知道其他对象是什么。
通知 和键值观察实现了观察者模式
第13章 组合模式
组合模式:将对象组合成树状结构以标示 部分-整体的层次结构,组合使得用户对单个对象和组合对象的使用具有一致性。
使用场景:
想获得对象抽象的树形表示
想让客户端统一处理组合结构中的所有对象
Cocoa Touch中的UIView 就是一个层次结构的例子。
第14章 迭代器
迭代器:提供一种方法顺序访问一个聚合对象中的各元素,而又不需暴露该对象的内部表示。
使用场景:需要访问组合对象的内容,而又不需暴露其内部表示
需要通过多种方式遍历组合对象
需要提供一个统一的接口,用来便利各种类型的组合对象。
NSEnumerator实现了迭代器模式。能够顺序遍历各种集合
快速枚举 forin,使用了指针运算
NSArray有个方法(void)makeObjectsPerformSelector:(SEL)aSelector;
第15章 访问者
访问者模式:表示一个作用于某对象结构中的各元素的操作,它让我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
应用场景:一个复杂的对象结构包含很多其它对象,它们有不同的接口(比如组合体),这些对象实施一些依赖于其它类型的操作。
需要对一个组合结构中的对象进行很多不相关的操作,但是不想让这些操作污染这些对象的类。可以将相关的操作集中起来,定义在一个访问者类中,并在需要在访问者中定义的操作时使用它。
定义复杂结构的类很少作修改,但经常需要向其添加新的操作。
第16章 装饰
装饰模式:动态地给一个对象添加一些额外的职责,就扩展功能来说,装饰模式相比生成子类更为灵活。
想要在不影响其它对象的情况下,以动态,透明的方式给耽搁对象添加职责。
想要扩展一个类的行为,却做不到。类定义可能被隐藏,无法进行子类化,或者,对类的每个行为的扩展,为支持每种功能的组合将产生大量的子类。
对类的职责的扩展是可选的。
可以通过 forwardingTargetForSelector:(SEL)aSelector 的方法或者
可以通过范畴实现装饰模式
定义基类的变化扩展类
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface UIImage (BaseFilter)
- (CGContextRef) beginContext;
- (UIImage *) getImageFromCurrentImageContext;
- (void) endContext;
@end
#import "UIImage+BaseFilter.h"
@implementation UIImage (BaseFilter)
- (CGContextRef) beginContext
{
// Create a graphics context with the target size
// On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions
// to take the scale into consideration
// On iOS prior to 4, fall back to use UIGraphicsBeginImageContext
CGSize size = [self size];
if (NULL != UIGraphicsBeginImageContextWithOptions)
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
else
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
return context;
}
- (UIImage *) getImageFromCurrentImageContext
{
[self drawAtPoint:CGPointZero];
// Retrieve the UIImage from the current context
UIImage *imageOut = UIGraphicsGetImageFromCurrentImageContext();
return imageOut;
}
- (void) endContext
{
UIGraphicsEndImageContext();
}
更加具体的一个扩展
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface UIImage (Transform)
- (UIImage *) imageWithTransform:(CGAffineTransform)transform;
@end
#import "UIImage+Transform.h"
#import "UIImage+BaseFilter.h"
@implementation UIImage (Transform)
- (UIImage *) imageWithTransform:(CGAffineTransform)transform
{
CGContextRef context = [self beginContext];
// setup transformation
CGContextConcatCTM(context, transform);
// Draw the original image to the context
UIImage *imageOut = [self getImageFromCurrentImageContext];
[self endContext];
return imageOut;
}
@end
第17章 责任链
责任链模式:使多个对象都有机会请求处理请求,从而避免请求的发送者何接收者之间发生耦合。此模式将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
使用场景:有多个对象可以处理请求,而处理程序直邮在运行时才能确定。
向一组对象发出请求,而不想显式指定处理请求的特定处理程序。
一个攻击游戏人物护甲的演示
攻击基类(什么也没有。。。)
#import <Foundation/Foundation.h>
@interface Attack : NSObject
{
}
@end
#import "Attack.h"
@implementation Attack
@end
护甲基类,有一个下一个处理者的属性,基类中定义了处理攻击的行为,会调用下一个处理者的该方法
#import <Foundation/Foundation.h>
#import "Attack.h"
@interface AttackHandler : NSObject
{
@private
AttackHandler *nextAttackHandler_;
}
@property (nonatomic, retain) AttackHandler *nextAttackHandler;
- (void) handleAttack:(Attack *)attack;
@end
#import "AttackHandler.h"
@implementation AttackHandler
@synthesize nextAttackHandler=nextAttackHandler_;
- (void) handleAttack:(Attack *)attack
{
[nextAttackHandler_ handleAttack:attack];
}
@end
金属护甲可以识别处理SwordAttack,如果处理成功了,伤害不再继续传递
#import <Foundation/Foundation.h>
#import "AttackHandler.h"
@interface MetalArmor : AttackHandler
{
}
// overridden method
- (void) handleAttack:(Attack *)attack;
@end
#import "MetalArmor.h"
#import "SwordAttack.h"
@implementation MetalArmor
- (void) handleAttack:(Attack *)attack
{
if ([attack isKindOfClass:[SwordAttack class]])
{
// no damage beyond this armor
NSLog(@"%@", @"No damage from a sword attack!");
}
else
{
NSLog(@"I don't know this attack: %@", [attack class]);
[super handleAttack:attack];
}
}
@end
水晶护甲可以识别处理MagicFireAttack,如果处理成功了,伤害不再继续传递,如果不能处理继续传递。
#import <Foundation/Foundation.h>
#import "AttackHandler.h"
@interface CrystalShield : AttackHandler
{
}
// overridden method
- (void) handleAttack:(Attack *)attack;
@end
#import "CrystalShield.h"
#import "MagicFireAttack.h"
@implementation CrystalShield
- (void) handleAttack:(Attack *)attack
{
if ([attack isKindOfClass:[MagicFireAttack class]])
{
// no damage beyond this shield
NSLog(@"%@", @"No damage from a magic fire attack!");
}
else
{
NSLog(@"I don't know this attack: %@", [attack class]);
[super handleAttack:attack];
}
}
@end
游戏人物,接收所有的伤害
#import <Foundation/Foundation.h>
#import "AttackHandler.h"
@interface Avatar : AttackHandler
{
}
// overridden method
- (void) handleAttack:(Attack *)attack;
@end
#import "Avatar.h"
@implementation Avatar
- (void) handleAttack:(Attack *)attack
{
// when an attack reaches this point,
// I'm hit.
// actual points taken off depends on
// the type of attack.
NSLog(@"Oh! I'm hit with a %@!", [attack class]);
}
@end
这个例子里面的伤害实现类都是基本没有内容的。。。
#import <Foundation/Foundation.h>
#import "Attack.h"
@interface SwordAttack : Attack
{
}
@end
#import "SwordAttack.h"
@implementation SwordAttack
@end
#import <Foundation/Foundation.h>
#import "Attack.h"
@interface MagicFireAttack : Attack
{
}
@end
#import "MagicFireAttack.h"
@implementation MagicFireAttack
@end
#import <Foundation/Foundation.h>
#import "Attack.h"
@interface LightningAttack : Attack
{
}
@end
#import "LightningAttack.h"
@implementation LightningAttack
@end
客户端调用
- (void)viewDidLoad
{
[super viewDidLoad];
// create a new avatar
AttackHandler *avatar = [[[Avatar alloc] init] autorelease];
// put it in metal armor
AttackHandler *metalArmoredAvatar = [[[MetalArmor alloc] init] autorelease];
[metalArmoredAvatar setAttackHandler:avatar];
// then add a crytal shield
// to the avatar who's in
// a metal armor
AttackHandler *superAvatar = [[[CrystalShield alloc] init] autorelease];
[superAvatar setAttackHandler:metalArmoredAvatar];
// ... some other actions
// attack the avatar with
// a sword
Attack *swordAttack = [[[SwordAttack alloc] init] autorelease];
[superAvatar handleAttack:swordAttack];
// then attack the avatar with
// magic fire
Attack *magicFireAttack = [[[MagicFireAttack alloc] init] autorelease];
[superAvatar handleAttack:magicFireAttack];
// now there is a new attack
// with lightning...
Attack *lightningAttack = [[[LightningAttack alloc] init] autorelease];
[superAvatar handleAttack:lightningAttack];
// ... further actions
}
第七部分
18模板方法
模板方法:定义一个操作中算法的骨架,而将一些步骤延迟到子类种中,模板方法使子类可以重定义算法的某些特定步骤而不改变该算法的结构。
使用场景:
需要一次性实现算法的不变部分,而将可变的行为留给子类来实现。
子类的共同行为应该被提取出来放到公共类中,以避免代码的重复。现有代码的差别应该被分离为新的操作。然后用一个调用这些新操作的木板方法来替换这些不同的代码。
需要控制子类的扩展。可以定义一个在特定点调用钩子操作的模板方法。子类可以通过对钩子操作的实现在这些点扩展功能。
制作三明治的例子来说
定义抽象基类,制作三明治的一般步骤
//AnySandwich.h
#import <Foundation/Foundation.h>
@interface AnySandwich : NSObject
{
}
- (void) make;
// Steps to make a sandwich
- (void) prepareBread;
- (void) putBreadOnPlate;
- (void) addMeat;
- (void) addCondiments;
- (void) extraStep;
- (void) serve;
@end
//AnySandwich.m
#import "AnySandwich.h"
@implementation AnySandwich
- (void) make
{
[self prepareBread];
[self putBreadOnPlate];
[self addMeat];
[self addCondiments];
[self extraStep];
[self serve];
}
- (void) putBreadOnPlate
{
// We need first to put bread on a plate for any sandwich.
}
- (void) serve
{
// Any sandwich will be served eventually.
}
#pragma mark -
#pragma Details will be handled by subclasses
- (void) prepareBread
{
[NSException raise:NSInternalInconsistencyException
format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)];
}
- (void) addMeat
{
[NSException raise:NSInternalInconsistencyException
format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)];
}
- (void) addCondiments
{
[NSException raise:NSInternalInconsistencyException
format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)];
}
- (void) extraStep{}
@end
汉堡类
//Hamburger.h
#import <Foundation/Foundation.h>
#import "AnySandwich.h"
@interface Hamburger : AnySandwich
{
}
- (void) prepareBread;
- (void) addMeat;
- (void) addCondiments;
//- (void) extraStep;
// Hamburger specific methods
- (void) getBurgerBun;
- (void) addKetchup;
- (void) addMustard;
- (void) addBeefPatty;
- (void) addCheese;
- (void) addPickles;
@end
//Hamburger.m
#import "Hamburger.h"
@implementation Hamburger
- (void) prepareBread;
{
[self getBurgerBun];
}
- (void) addMeat
{
[self addBeefPatty];
}
- (void) addCondiments
{
[self addKetchup];
[self addMustard];
[self addCheese];
[self addPickles];
}
#pragma mark -
#pragma mark Hamburger Specific Methods
- (void) getBurgerBun
{
// A hamburger needs a bun.
}
- (void) addKetchup
{
// Before adding anything to a bun, we need to put ketchup.
}
- (void) addMustard
{
// Then add some mustard.
}
- (void) addBeefPatty
{
// A piece of beef patty is the main character in a burger.
}
- (void) addCheese
{
// Let's just assume every burger has cheese.
}
- (void) addPickles
{
// Then finally add some pickles to it.
}
@end
热狗类
//Hotdog.h
#import <Foundation/Foundation.h>
#import "AnySandwich.h"
@interface Hotdog : AnySandwich
{
}
- (void) prepareBread;
- (void) addMeat;
- (void) addCondiments;
//- (void) extraStep;
// Hotdog specific methods
- (void) getHotdogBun;
- (void) addWiener;
- (void) addKetchup;
- (void) addMustard;
- (void) addOnion;
@end
//Hotdog.m
#import "Hotdog.h"
@implementation Hotdog
- (void) prepareBread
{
[self getHotdogBun];
}
- (void) addMeat
{
[self addWiener];
}
- (void) addCondiments
{
[self addKetchup];
[self addMustard];
[self addOnion];
}
#pragma mark -
#pragma mark Hotdog Specific Methods
- (void) getHotdogBun
{
// First of all, we need a hotdog bun.
}
- (void) addWiener
{
// A nice piece of wiener is the main character here.
}
- (void) addKetchup
{
// Every hotdog needs ketchup.
}
- (void) addMustard
{
// I think mustard is also needed.
}
- (void) addOnion
{
// I think adding onion is a good idea.
}
@end
19策略
策略模式:定义一系列的算法,把它们一个个封装起来,并且使它们可互相替换。本模式使得算法可独立于使用它的客户而变化。
一个类在其操作中使用多个条件语句来定义许多行为。我们可以把相关的条件分支移到它们自己的策略类种功能。
需要算法的各种变体
需要避免把复杂的与算法相关的数据结构暴露给客户端。
- (BOOL)validateInput:(UITextField *)input error:(NSError **)error;
采用error参数可以传递错误信息,引用UITextField参数可以对输入框作相应的修改。
- (BOOL)validateInput:(UITextField*)input error:(NSError **)error{
NSError *regError = nil;
NSRegularExpression *regx = [NSRegularExpression regularExpressionWithPattern:@"^[0-9]*$" options:NSRegularExpressionAnchorsMatchLines error:®Error];
NSUInteger numberOfMatches = [regx numberOfMatchesInString:[input text] options:NSMatchingAnchored range:NSMakeRange(0, [[input text]length])];
if (numberOfMatches == 0) {
if (error != nil) {
NSString *description = NSLocalizedString(@"Input Validation Failed", @"") ;
NSString *reason = NSLocalizedString(@"The input can contain only numberic values", @"") ;
NSArray *objArray = [NSArray arrayWithObjects:description,reason, nil];
NSArray *keyArray = [NSArray arrayWithObjects:NSLocalizedDescriptionKey,NSLocalizedFailureReasonErrorKey, nil];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjects:objArray forKeys:keyArray];
*error = [NSError errorWithDomain:@"InptValidationErrorDomain" code:1001 userInfo:userInfo];
}
return NO;
}
return YES;
}
如果直接调用汉堡的基类,会报错
//不可以直接调用抽象基类,会报错
AnySandwich * sandwich = [[AnySandwich alloc] init];
[sandwich make];
//具体的子类可以直接调用
AnySandwich *hotdog = [[Hotdog alloc]init];
[hotdog make];
20命令
命令模式:将请求封装为一个对象,从而可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
想让应用程序支持撤销与恢复。
想用对象参数话一个动作以执行操作,并用不同命令对象来代替回调函数。
想要在不同的时刻对请求进行指定,排序和执行。
想记录修改日日志,这样在系统故障时,这些修改可在后来重做一遍。
想让系统支持事务,事务封装了对数据的一系列修改。事务可以建模为命令对象。
NSInvocation
NSUndoManager
第八部分 性能与对象访问
第21章享元模式
享元模式(Flyweight pattern): 运用共享技术有效地支持大量细粒度的对象。
当满足所有条件时,自然会考虑使用这个模式:
应用程序使用很多对象
在内存中保存对象会影响内存性能
对象的多数特有状态可以放到外部而轻量化
移除外在状态后,可以用较少的共享对象替代原来的那组对象。
应用程序不依赖于对象标识,因为共享对象不能提供唯一的标识。
百花池 效果
定义了一个FlowerView用来展示花朵
//FlowerView.h 文件
#import <Foundation/Foundation.h>
#import "UIKit/UIKit.h"
@interface FlowerView : UIImageView
@end
//FlowerView.m 文件
#import "FlowerView.h"
@implementation FlowerView
- (void) drawRect:(CGRect)rect
{
[self.image drawInRect:rect];
}
@end
定义了一个工厂方法来产生FlowerView
//FlowerFactory.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
typedef enum
{
kAnemone,
kCosmos,
kGerberas,
kHollyhock,
kJasmine,
kZinnia,
kTotalNumberOfFlowerTypes
} FlowerType;
@interface FlowerFactory : NSObject
{
@private
NSMutableDictionary *flowerPool_;
}
- (UIView *) flowerViewWithType:(FlowerType)type;
@end
//FlowerFactory.m
#import "FlowerFactory.h"
#import "FlowerView.h"
@implementation FlowerFactory
- (UIView *) flowerViewWithType:(FlowerType)type
{
// lazy-load a flower pool
if (flowerPool_ == nil)
{
flowerPool_ = [[NSMutableDictionary alloc]
initWithCapacity:kTotalNumberOfFlowerTypes];
}
// try to retrieve a flower
// from the pool
UIView *flowerView = [flowerPool_ objectForKey:[NSNumber
numberWithInt:type]];
// if the type requested
// is not available then
// create a new one and
// add it to the pool
if (flowerView == nil)
{
UIImage *flowerImage;
switch (type)
{
case kAnemone:
flowerImage = [UIImage imageNamed:@"anemone.png"];
break;
case kCosmos:
flowerImage = [UIImage imageNamed:@"cosmos.png"];
break;
case kGerberas:
flowerImage = [UIImage imageNamed:@"gerberas.png"];
break;
case kHollyhock:
flowerImage = [UIImage imageNamed:@"hollyhock.png"];
break;
case kJasmine:
flowerImage = [UIImage imageNamed:@"jasmine.png"];
break;
case kZinnia:
flowerImage = [UIImage imageNamed:@"zinnia.png"];
break;
default:
break;
}
flowerView = [[FlowerView alloc]
initWithImage:flowerImage];
[flowerPool_ setObject:flowerView
forKey:[NSNumber numberWithInt:type]];
}
return flowerView;
}
保存flowerview的状态
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface ExtrinsicFlowerState : NSObject
@property (nonatomic,strong) UIView *flowerView;
@property (nonatomic,assign) CGRect area;
@end
#import "ExtrinsicFlowerState.h"
@implementation ExtrinsicFlowerState
@end
控制器中调用代码
- (void)viewDidLoad {
[super viewDidLoad];
// construct a flower list
FlowerFactory *factory = [[FlowerFactory alloc] init];
NSMutableArray *flowerList = [[NSMutableArray alloc]
initWithCapacity:500];
for (int i = 0; i < 5000; ++i)
{
// retrieve a shared instance
// of a flower flyweight object
// from a flower factory with a
// random flower type
FlowerType flowerType = arc4random() % kTotalNumberOfFlowerTypes;
UIView *flowerView = [factory flowerViewWithType:flowerType];
// set up a location and an area for the flower
// to display onscreen
CGRect screenBounds = [[UIScreen mainScreen] bounds];
CGFloat x = (arc4random() % (NSInteger)screenBounds.size.width);
CGFloat y = (arc4random() % (NSInteger)screenBounds.size.height);
NSInteger minSize = 10;
NSInteger maxSize = 50;
CGFloat size = (arc4random() % (maxSize - minSize + 1)) + minSize;
// assign attributes for a flower
// to an extrinsic state object
ExtrinsicFlowerState * extrinsicState =[[ ExtrinsicFlowerState alloc]init];
extrinsicState.flowerView = flowerView;
extrinsicState.area = CGRectMake(x, y, size, size);
// add an extrinsic flower state
// to the flower list
[flowerList addObject: extrinsicState ];
}
// add the flower list to
// this FlyweightView instance
FlyweightView *flyWeightView = [[FlyweightView alloc]initWithFrame:CGRectMake(0, 0, 320, 640)];
flyWeightView.backgroundColor = [UIColor orangeColor];
[flyWeightView setFlowerList:flowerList];
[self.view addSubview:flyWeightView];
// Do any additional setup after loading the view, typically from a nib.
}
这样处理比直接在self.view 上添加 UIImageView还是节约了很多内存开销的,效果如下
22 代理
代理模式:为其它对象提供一种代理以控制对这个对象的访问。
需要一个远程代理,为处于不同地质空间或者网络中的对象提供本地带遍。
需要一个虚拟代理,为根据要求创建重型的对象。
需要一个保护代理,来控制不同访问权限对原对象的访问。
需要一个智能引用代理,通过对实体对象的引用来进行计数来管理内存。也能用户锁定实体对象,让其它对象不能修改它。
23备忘录
备忘录模式:在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原来保存的状态。
Cocoa Touch NSKeyedArchiver NSKeyedUnarchiver
NSCoding 协议
参考资料
Pro Objective C Design Pattern for iOS Objective C编程之道iOS设计模式解析
https://github.com/iossvis/Objective-C-Design-Patterns-for-IOS----Carlo-Chung-book-s-code