参考:《Objective-C编程之道》html
这边文章是在学习了《Objective-C编程之道》后的作的一些笔记,在其中参考了其余相关书籍或者其余前辈的例子以及一些文章内容,有引用到的地方我已经尽可能添加原文连接或者引用了,若是发现本文侵权可联系删除.node
此篇文章主要是对各个模式对介绍,此处引用对例子是我认为比较合适比较容易理解对例子,不过也会有一些片面,没法彻底解决各个模式.这篇文章总的来讲适合用来入门设计模式.ios
此篇文章可能会有不少不足之处,欢迎你们指出批评,也欢迎你们一块儿来学习探讨.c++
使用原型实例指定建立对象的种类,并经过复制这个原型建立新的对象.git
数据模型间的复制github
Student *s1 = [[Student alloc] init];
s1.age = 18;
s1.name = @"s1";
s1.address = @"adress";
s1.size = CGSizeMake(100, 100);
s1.teacher = p1;
s1.friends = @[p1, p2];
s1.girlfriends = [[NSMutableArray alloc] initWithArray:s1.friends];
s1.other = @[s1.friends, s1.girlfriends];
Student *s2 = [s1 copy];
复制代码
这里经过copy
可以拷贝获得一个数据一致的Student
.算法
这里须要特别注意的是浅复制和深复制之间的区别.macos
+ (UITableViewCell *)cellWithText:(NSString *)text {
LabelTableViewCell *cell = [[LabelTableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil];
cell.textLabel.text = text;
return cell;
}
+ (UITableViewCell *)cellWithImage:(UIImage *)img {
ImageTableViewCell *cell = [[ImageTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cell.imageView.image = img;
return cell;
}
+ (UITableViewCell *)cellWithSelect:(BOOL)isSelect {
SwitchTableViewCell *cell = [[SwitchTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
[cell setSwitchSelect:isSelect];
return cell;
}
复制代码
在iOS
中能够参考系统类NSNumber
;编程
- (NSNumber *)initWithChar:(char)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedChar:(unsigned char)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithShort:(short)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedShort:(unsigned short)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithInt:(int)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedInt:(unsigned int)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithLong:(long)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedLong:(unsigned long)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithLongLong:(long long)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedLongLong:(unsigned long long)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithFloat:(float)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithDouble:(double)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithBool:(BOOL)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithInteger:(NSInteger)value API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)) NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedInteger:(NSUInteger)value API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)) NS_DESIGNATED_INITIALIZER;
复制代码
提供一个建立一系列相关或相互依赖对象的接口,而无需指定他们具体的类.canvas
Cell
抽象工厂类AbstractFactory
@interface AbstractFactory : NSObject
+ (UITableViewCell *)cellWithText:(NSString *)text;
+ (UITableViewCell *)cellWithImage:(UIImage *)img;
@end
复制代码
继承AbstractFactory
的普通工厂类CellFactory
@implementation CellFactory
+ (UITableViewCell *)cellWithText:(NSString *)text {
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil];
cell.textLabel.text = text;
return cell;
}
+ (UITableViewCell *)cellWithImage:(UIImage *)img {
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cell.imageView.image = img;
return cell;
}
@end
复制代码
继承AbstractFactory
的可点击Cell
工厂类CellFactory
@implementation ClickFactory
+ (UITableViewCell *)cellWithText:(NSString *)text {
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil];
cell.textLabel.text = text;
cell.textLabel.userInteractionEnabled = YES;
return cell;
}
+ (UITableViewCell *)cellWithImage:(UIImage *)img {
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cell.imageView.image = img;
cell.imageView.userInteractionEnabled = YES;
return cell;
}
@end
复制代码
控制器实现
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
switch (indexPath.row % 2) {
case 0:
if (indexPath.row > 2) {
cell = [ClickFactory cellWithText:[NSString stringWithFormat:@"%ld", indexPath.row]];
} else {
cell = [CellFactory cellWithText:[NSString stringWithFormat:@"%ld", indexPath.row]];
}
break;
case 1:
if (indexPath.row > 2) {
cell = [ClickFactory cellWithImage:[UIImage imageNamed:@"12.png"]];
} else {
cell = [CellFactory cellWithImage:[UIImage imageNamed:@"12.png"]];
}
break;
case 2:
break;
default:
break;
}
return cell;
}
复制代码
抽象工厂与工厂模式在许多方面都很是相似.不少人经常搞不清楚应该在何时用哪个.两个模式都用于相同的目的:建立对象而不让客户端知晓返回了什么确切的具体对象.
抽象工厂 | 工厂方法 |
---|---|
经过对象组合建立抽象产品 | 经过类继承建立抽象产品 |
建立多系列产品 | 建立一种产品 |
必须修改父类的接口才能支持新的产品 | 子类化建立者并重载工厂方法以建立新产品 |
抽象工厂模式是一种极为常见的设计模式.它是最基本的,由于它能够涉及许多类型的对象建立.一系列相关类的好的模式,应该做为一种抽象,不为客户端所见.抽象工厂能够顺畅地提供这种抽象,而不暴露建立过程当中任何没必要要的细节或所建立对象的确切类型.
将一个复杂对象的构建与它的表现分离,使得一样的构建过程能够建立不一样的表现.
须要建立涉及各类部件的复杂对象.建立对象的算法应该独立于部件的装配方式.常见例子是构建组合对象.
构建过程须要以不一样的方式构建对象.
定义指导者类SandwichDirector
@interface SandwichDirector : NSObject
// 具体的生成类
@property (nonatomic, strong) id<SandwichBuilder> concreteBuilder;
// 生成动做
- (void)construct;
@end
规定制做三明治流程
@implementation SandwichDirector
- (void)construct {
[_concreteBuilder prepareBread];
[_concreteBuilder addMeat];
}
@end
复制代码
@protocol SandwichBuilder <NSObject>
- (void)prepareBread;
- (void)addMeat;
@end
复制代码
基础三明治类Sandwich
@interface Sandwich : NSObject
@property (nonatomic, copy) NSString *breadType;
@property (nonatomic, copy) NSString *meatType;
@end
复制代码
制做鲁宾三明治类SandwichConcreteBuilder
@interface SandwichConcreteBuilder : NSObject<SandwichBuilder>
// 获取生成的三明治
- (Sandwich *)getSandwich;
@end
@interface SandwichConcreteBuilder ()
@property (nonatomic, strong) Sandwich *reubenSandwich;
@end
@implementation SandwichConcreteBuilder
- (instancetype)init {
if (self = [super init]) {
_reubenSandwich = [[Sandwich alloc] init];
}
return self;
}
- (void)prepareBread {
_reubenSandwich.breadType = @"黑麦面包";
}
- (void)addMeat {
_reubenSandwich.meatType = @"腌牛肉";
}
- (id)getSandwich {
return _reubenSandwich;
}
复制代码
获取鲁宾三明治
SandwichDirector *director = [[SandwichDirector alloc] init];
SandwichConcreteBuilder *builder = [[SandwichConcreteBuilder alloc] init];
[director setConcreteBuilder:builder];
[director construct];
Sandwich *sandwich = [builder getSandwich];
NSLog(@"面包:%@\n肉:%@", sandwich.breadType, sandwich.meatType);
复制代码
生成器模式能帮助构建涉及部件与表现的各类组合的对象.没有这一模式,知道构建对象所需细节的Director
可能最终会变成一个庞大的"神"类,带有无数用于构建同一个类的各类表现的内嵌算法.
保证一个类仅有一个实例,并提供一个访问它的全局访问点.
@interface Singleton : NSObject
/// 统一的接口
+ (instancetype)defaultSingleton;
@end
static Singleton *_singleton;
@implementation Singleton
+ (instancetype)defaultSingleton {
return [[self alloc] init];
}
- (instancetype)init {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_singleton = [super init];
});
return _singleton;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
if (!_singleton) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_singleton = [super allocWithZone:zone];
});
}
return _singleton;
}
- (id)copy {
return _singleton;
}
- (id)mutableCopy {
return _singleton;
}
@end
复制代码
由于单例只会存在一个对象,因此sigleton0
和sigleton1
是等价的.
Singleton *sigleton0 = [[Singleton alloc] init];
NSLog(@"%@", sigleton0);
Singleton *sigleton1 = [Singleton defaultSingleton];
NSLog(@"%@", sigleton1);
NSLog(@"%@", [sigleton0 copy]);
NSLog(@"%@", [sigleton1 mutableCopy]);
复制代码
几乎在任何类型的应用程序中,单例模式都极为常见,并不仅限于iOS应用程序开发.只要应用程序须要用集中式的类来协调其服务,这个类就应生成单一的实例,而不是多个实例.
将一个类的接口转换成客户但愿的另一个接口.适配器模式使得本来因为接口不兼容而不能一块儿工做的那些类能够一块儿工做.
类适配器类图
对象适配器类图
初始请求目标执行类
@interface Target : NSObject
- (void)request;
@end
@implementation Target
- (void)request {
NSLog(@"请求");
}
@end
复制代码
新的执行类
@interface Adaptee : NSObject
- (void)specialRequest;
@end
@implementation Adaptee
- (void)specialRequest {
NSLog(@"特殊请求");
}
@end
复制代码
适配器类实现
@interface Adapter : Target
@property (nonatomic, strong) Adaptee *adaptee;
@end
@implementation Adapter
- (instancetype)init {
if (self = [super init]) {
self.adaptee = [[Adaptee alloc] init];
}
return self;
}
- (void)request {
[self.adaptee specialRequest];
}
@end
复制代码
控制器调用
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Target *target = [[Adapter alloc] init];
[target request];
}
@end
复制代码
适配器模式能够用做为目标接口的协议来实现,协议定义客户端要求的,也是适配器能够保证的一些标准行为.协议是Object-C
中语言级别的功能,经过它能够定义用做适配器模式的实例的接口.
将抽象部分与它的实现部分分离,使它们均可以独立地变化.
接口协议MessageImplement
@protocol MessageImplement <NSObject>
- (void)sendMessage:(NSString *)message;
@end
复制代码
抽象信息类AbstractMessage
/// 抽象信息类
@interface AbstractMessage : NSObject
@property (nonatomic, strong) id<MessageImplement> messageIm;
- (void)send:(NSMutableString *)message;
- (instancetype)initWithImplement:(id<MessageImplement>)implement;
@end
@implementation AbstractMessage
- (instancetype)initWithImplement:(id<MessageImplement>)implement {
if (self = [super init]) {
self.messageIm = implement;
}
return self;
}
- (void)send:(NSMutableString *)message {
}
@end
复制代码
普通讯息类CommonMessage
/// 普通讯息类
@interface CommonMessage : AbstractMessage
@end
@implementation CommonMessage
- (void)send:(NSMutableString *)message {
[message insertString:@"【普通消息:" atIndex:0];
[message appendString:@"】"];
[self.messageIm sendMessage:message];
}
@end
复制代码
QQ信息类QQMessage
/// QQ信息类
@interface QQMessage : AbstractMessage
@end
@implementation QQMessage
- (void)send:(NSMutableString *)message {
[message insertString:@"【QQ消息:" atIndex:0];
[message appendString:@"】"];
[self.messageIm sendMessage:message];
}
@end
复制代码
系统发送类MessageSMS
/// 系统发送类
@interface MessageSMS : NSObject<MessageImplement>
@end
@implementation MessageSMS
- (void)sendMessage:(NSString *)message {
NSLog(@"使用系统发送消息:%@", message);
}
@end
复制代码
手机发送类MessageTEL
/// 手机发送类
@interface MessageTEL : NSObject<MessageImplement>
@end
@implementation MessageTEL
- (void)sendMessage:(NSString *)message {
NSLog(@"使用手机发送消息:%@", message);
}
@end
复制代码
控制器实现
- (void)viewDidLoad {
[super viewDidLoad];
MessageSMS *sms = [[MessageSMS alloc] init];
MessageTEL *tel = [[MessageTEL alloc] init];
QQMessage *messageSMS = [[QQMessage alloc] initWithImplement:sms];
[messageSMS send:[[NSMutableString alloc] initWithString:@"SMS->QQ"]];
NSLog(@"\n");
QQMessage *messageTEL = [[QQMessage alloc] initWithImplement:tel];
[messageTEL send:[[NSMutableString alloc] initWithString:@"TEL->QQ"]];
NSLog(@"\n");
CommonMessage *commonSMS = [[CommonMessage alloc] initWithImplement:sms];
[commonSMS send:[[NSMutableString alloc] initWithString:@"SMS->Common"]];
NSLog(@"\n");
CommonMessage *commonTEL = [[CommonMessage alloc] initWithImplement:tel];
[commonTEL send:[[NSMutableString alloc] initWithString:@"TEL->Common"]];
}
@end
复制代码
结果展现
2019-04-10 22:25:22.611392+0800 BridgePattern[46027:874792] 使用系统发送消息:【QQ消息:SMS->QQ】
2019-04-10 22:25:22.611661+0800 BridgePattern[46027:874792]
2019-04-10 22:25:25.998905+0800 BridgePattern[46027:874792] 使用手机发送消息:【QQ消息:TEL->QQ】
2019-04-10 22:25:25.999066+0800 BridgePattern[46027:874792]
2019-04-10 22:25:25.999229+0800 BridgePattern[46027:874792] 使用系统发送消息:【普通消息:SMS->Common】
2019-04-10 22:25:25.999343+0800 BridgePattern[46027:874792]
2019-04-10 22:25:25.999468+0800 BridgePattern[46027:874792] 使用手机发送消息:【普通消息:TEL->Common】
复制代码
桥接模式是把一个接口适配到不一样接口的一种方式.
为系统中的一组接口提供一个统一的接口.外观定义一个高层接口,让子系统更易于使用.
子系统正逐渐变得复杂.应用模式的过程当中演化出许多类.可使用外观为这些子系统提供一个简单的接口.
可使用外观对子系统进行分层.每一个子系统级别有一个外观做为入口点.让它们经过其外观进行通讯,能够简化它们的依赖关系.
定义汽车类Car
@interface Car : NSObject
- (void)releaseBreaks;
- (void)changeGears;
- (void)pressAccelerator;
- (void)pressBreaks;
- (void)releaseAccelerator;
@end
@implementation Car
- (void)releaseBreaks {
NSLog(@"松开刹车");
}
- (void)changeGears {
NSLog(@"换挡");
}
- (void)pressAccelerator {
NSLog(@"踩油门");
}
- (void)pressBreaks {
NSLog(@"松油门");
}
- (void)releaseAccelerator {
NSLog(@"刹车");
}
@end
复制代码
计价器类Taximeter
实现
@interface Taximeter : NSObject
- (void)start;
- (void)stop;
@end
@implementation Taximeter
- (void)start {
NSLog(@"启动计价器");
}
- (void)stop {
NSLog(@"停下计价器");
}
复制代码
外观类CabDriver
的driveToLocation
接口整合Taximeter
Car
子系统为外部提供接口
@interface CabDriver : NSObject
- (void)driveToLocation:(CGPoint)x;
@end
@implementation CabDriver
- (void)driveToLocation:(CGPoint)x {
// 启动计价器
Taximeter *meter = [[Taximeter alloc] init];
[meter start];
// 操做车辆,直到抵达位置
Car *car = [[Car alloc] init];
[car releaseBreaks];
[car changeGears];
[car pressAccelerator];
// 当到达了位置x,就停下车和计价器
[car releaseAccelerator];
[car pressBreaks];
[meter stop];
}
@end
复制代码
外观有助于提供一种更为简洁的方式来使用子系统中的这些类.处理这些子系统类的默认行为,可能只是定义在外观的一个简便方法,而没必要直接去使用这些类时即可以使用外观设计模式了.
用一个对象来封装一系列对象的交互方式.中介者使对象不须要显式地相互引用,从而使其耦合松散,并且能够独立地改变它们之间的交互.
原文: Objective-C设计模式——中介者Mediator
中介者模式很好的诠释了迪米特法则,任意两个不相关的对象之间若是须要关联,那么须要经过第三个类来进行。中介者就是把一组对象进行封装,屏蔽了类之间的交互细节,使不一样的类直接不须要持有对方引用也能够进行访问。
中介者Mediator
会持有同事类(就是须要处理交互逻辑的对象)Colleague
的引用,同时每一个colleague
也会持有Mediator
一份引用。这样colleague
若是有任何和别的类交互的请求就会发给Mediator
,对改组对象进行了解耦合。其实咱们平时常常写的视图控制器自己就是一个中介者,它来控制着不一样对象之间的交互行为。
中介者Mediator
@interface Mediator : NSObject
@property (nonatomic, weak) ColleagueA *collA;
@property (nonatomic, weak) ColleagueB *collB;
- (void)notify:(id)obj;
@end
@implementation Mediator
- (void)notify:(id)obj {
if (obj == self.collA) {
[self.collB notified:@"B Notified"];
} else {
[self.collA notified:@"A Notified"];
}
}
@end
复制代码
同事类基类Colleague
@interface Colleague : NSObject
@property (nonatomic, weak) Mediator *mediator;
- (instancetype)initWithMediator:(Mediator *)mediator;
- (void)notifyAnother;
- (void)notified:(NSString *)message;
@end
@implementation Colleague
- (instancetype)initWithMediator:(Mediator *)mediator {
if (self = [super init]) {
self.mediator = mediator;
}
return self;
}
- (void)notifyAnother {
[self.mediator notify:self];
}
- (void)notified:(NSString *)message {
NSLog(@"%@", message);
}
@end
复制代码
同事类AColleagueA
@interface ColleagueA : Colleague
@end
@implementation ColleagueA
@end
复制代码
设置同事类BColleagueB
与同事类A一致
控制器实现
Mediator *mediator = [[Mediator alloc] init];
ColleagueA *caA = [[ColleagueA alloc] initWithMediator:mediator];
ColleagueB *caB = [[ColleagueB alloc] initWithMediator:mediator];
mediator.collA = caA;
mediator.collB = caB;
[caA notifyAnother];
[caB notifyAnother];
复制代码
结果展现
2019-04-18 23:27:55.290764+0800 MediatorPattern[86780:1876003] B Notified
2019-04-18 23:27:55.290933+0800 MediatorPattern[86780:1876003] A Notified
复制代码
虽然对于处理应用程序的行为分散于不一样对象而且对象相互依存的状况,中介者模式很是有用,可是应当注意避免让中介者过于庞大而难以维护.若是已经这样了,能够考虑使用另外一种设计模式把它分解.要创造性地混用和组合各类设计模式解决同一个问题.
扩展: 组件化和模块化间用于各个模块的跳转交互所用的就是中介者模式.
Cocoa Touch
框架中使用的观察者模式--通知和键-值观察定义模型类Person
UIKIT_EXTERN NSNotificationName const PersonNameWillChangeNotification;
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end
NSNotificationName const PersonNameWillChangeNotification = @"PersonNameWillChangeNotification";
@implementation Person
- (void)setName:(NSString *)name {
_name = name;
// 发送通知
[[NSNotificationCenter defaultCenter] postNotificationName:PersonNameWillChangeNotification object:_name];
}
@end
复制代码
控制器实现
对象赋初值
_xiaoming = [[Person alloc] init];
_xiaoming.name = @"xiaoming";
_xiaoming.age = 11;
复制代码
经过通知监听名字更替
// 通知更换了名字
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changePersonName:) name:PersonNameWillChangeNotification object:nil];
_xiaoming.name = @"wangxiaoming";
- (void)changePersonName:(NSNotification *)noti {
NSLog(@"newName = %@", noti.object);
}
//2019-03-29 22:39:23.243012+0800 ObserverPattern[9755:1317800] newName = wangxiaoming
复制代码
经过键-值观察监听年龄变化
[self.xiaoming addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
_xiaoming.age = 28;
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
NSLog(@"newAge = %ld", [change[NSKeyValueChangeNewKey] integerValue]);
//2019-03-29 22:39:23.243229+0800 ObserverPattern[9755:1317800] newAge = 28
}
复制代码
具体实现
- (void)viewDidLoad {
[super viewDidLoad];
_xiaoming = [[Person alloc] init];
_xiaoming.name = @"xiaoming";
_xiaoming.age = 11;
// 通知更换了名字
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changePersonName:) name:PersonNameWillChangeNotification object:nil];
// 监听xiaoming年龄变化
[self.xiaoming addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
_xiaoming.name = @"wangxiaoming";
_xiaoming.age = 28;
// 移除相关监听
[[NSNotificationCenter defaultCenter] removeObserver:self name:PersonNameWillChangeNotification object:nil];
[self.xiaoming removeObserver:self forKeyPath:@"age"];
}
- (void)changePersonName:(NSNotification *)noti {
NSLog(@"newName = %@", noti.object);
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
NSLog(@"newAge = %ld", [change[NSKeyValueChangeNewKey] integerValue]);
}
复制代码
通知和KVO
是iOS
中经常使用的数据交互传输的两种手段.特别是在需求须要双向绑定的状况下KVO
是很是适合使用的.开发中可使用KVO
来实现类MVVM
这样的框架.
将对象组合成树形结构以表示"部分-总体"的层次结构.组合使得用户对单个对象和组合对象的使用具备一致性.
原文: 组合模式(Composite)
定义基础组件类Components
@interface Components : NSObject
@property (nonatomic, copy) NSString *name;
- (instancetype)initWithName:(NSString *)name;
- (void)addComponent:(Components *)component;
- (void)removeComponent:(Components *)component;
- (void)display:(NSInteger)depth;
@end
@implementation Components
- (instancetype)initWithName:(NSString *)name {
if (self = [super init]) {
self.name = name;
}
return self;
}
- (void)addComponent:(Components *)component {
return;
}
- (void)removeComponent:(Components *)component {
return;
}
- (void)display:(NSInteger)depth {
return;
}
@end
复制代码
定义叶子的子类Leaf
@interface Leaf : Components
@end
@implementation Leaf
- (void)addComponent:(Components *)component {
NSLog(@"can not add");
}
- (void)removeComponent:(Components *)component {
NSLog(@"can not remove");
}
- (void)display:(NSInteger)depth {
NSLog(@"[level:%ld_%@]",depth, self.name);
}
@end
复制代码
定义节点类Composite
,节点可包含新节点或新叶子
@interface Composite : Components
@property (nonatomic, strong) NSMutableArray *childArr;
@end
@implementation Composite
- (instancetype)initWithName:(NSString *)name {
if (self = [super initWithName:name]) {
self.childArr = [[NSMutableArray alloc] init];
}
return self;
}
- (void)addComponent:(Components *)component {
[self.childArr addObject:component];
}
- (void)removeComponent:(Components *)component {
[self.childArr removeObject:component];
}
- (void)display:(NSInteger)depth {
NSLog(@"[level:%ld_%@]",depth, self.name);
for (Components *component in self.childArr) {
[component display:depth + 1];
}
}
@end
复制代码
控制器实现
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Composite *root = [[Composite alloc] initWithName:@"root"];
[root addComponent:[[Leaf alloc] initWithName:@"leaf-A"]];
[root addComponent:[[Leaf alloc] initWithName:@"leaf-B"]];
Composite *comp0 = [[Composite alloc] initWithName:@"comp0"];
[comp0 addComponent:[[Leaf alloc] initWithName:@"comp0-A"]];
[comp0 addComponent:[[Leaf alloc] initWithName:@"comp0-B"]];
[root addComponent:comp0];
Composite *comp1 = [[Composite alloc] initWithName:@"comp1"];
[comp1 addComponent:[[Leaf alloc] initWithName:@"comp1-A"]];
[comp1 addComponent:[[Leaf alloc] initWithName:@"comp1-B"]];
[root addComponent:comp1];
Composite *comp00 = [[Composite alloc] initWithName:@"comp00"];
[comp00 addComponent:[[Leaf alloc] initWithName:@"comp00-A"]];
[comp00 addComponent:[[Leaf alloc] initWithName:@"comp00-B"]];
[comp0 addComponent:comp00];
Leaf *leafC = [[Leaf alloc] initWithName:@"leaf-C"];
[root addComponent:leafC];
[root addComponent:[[Leaf alloc] initWithName:@"leaf-D"]];
[root display:0];
NSLog(@"-------- 删除leaf-C --------");
// 删除leaf-C
[root removeComponent:leafC];
[root display:0];
NSLog(@"-------- 删除comp0 --------");
// 删除comp0
[root removeComponent:comp0];
[root display:0];
}
@end
复制代码
结果展现
[level:0_root]
[level:1_leaf-A]
[level:1_leaf-B]
[level:1_comp0]
[level:2_comp0-A]
[level:2_comp0-B]
[level:2_comp00]
[level:3_comp00-A]
[level:3_comp00-B]
[level:1_comp1]
[level:2_comp1-A]
[level:2_comp1-B]
[level:1_leaf-C]
[level:1_leaf-D]
-------- 删除leaf-C --------
[level:0_root]
[level:1_leaf-A]
[level:1_leaf-B]
[level:1_comp0]
[level:2_comp0-A]
[level:2_comp0-B]
[level:2_comp00]
[level:3_comp00-A]
[level:3_comp00-B]
[level:1_comp1]
[level:2_comp1-A]
[level:2_comp1-B]
[level:1_leaf-D]
-------- 删除comp0 --------
[level:0_root]
[level:1_leaf-A]
[level:1_leaf-B]
[level:1_comp1]
[level:2_comp1-A]
[level:2_comp1-B]
[level:1_leaf-D]
复制代码
Cocoa Touch
框架中,UIView
被组织成一个组合结构.每一个UIView
的实例能够包含UIView
的其余实例,造成统一的树形结构.让客户端对单个UIView
对象和UIView
的组合统一对待.
组合模式的主要意图是让树形结构中的每一个节点具备相同的抽象接口.这样整个结构可做为一个统一的抽象结构使用,而不暴露其内部展现.对每一个节点(叶节点或组合体)的任何操做,能够经过协议或抽象基类中定义的相同接口来进行.
提供一种方法顺序访问一个聚合对象中各个元素,而又不须要暴露该对象的内部表示.
List
与ListIterator
之间关系的类图
抽象列表与迭代器之间关系的类图
参考:iOS设计模式--迭代器
// 系统迭代器
NSArray *arr = @[@"A", @"B", @"C", @"D"];
NSEnumerator *enumerator = [arr objectEnumerator];
NSString *obj = nil;
while ((obj = enumerator.nextObject)) {
NSLog(@"%@", obj);
}
复制代码
定义节点类Node
@interface Node : NSObject
/// 下一节点
@property (nonatomic, strong) Node *nextNode;
@property (nonatomic, strong) NSString *nodeName;
+ (instancetype)nodeWithName:(NSString *)name;
@end
@implementation Node
+ (instancetype)nodeWithName:(NSString *)name {
Node *node = [[Node alloc] init];
node.nodeName = name;
return node;
}
@end
复制代码
定义链表类LinkedList
@interface LinkedList : NSObject
@property (nonatomic, strong, readonly) Node *firstNode;
@property (nonatomic, assign, readonly) NSInteger count;
- (void)addItem:(NSString *)item;
@end
@interface LinkedList ()
@property (nonatomic, strong) Node *firstNode;
@property (nonatomic, assign) NSInteger count;
@end
@implementation LinkedList
- (void)addItem:(NSString *)item {
if (self.firstNode == nil) {
self.firstNode = [Node nodeWithName:item];
self.count++;
} else {
[self addItem:item node:self.firstNode];
}
}
- (void)addItem:(NSString *)item node:(Node *)node {
if (!node.nextNode) {
node.nextNode = [Node nodeWithName:item];
self.count++;
} else {
[self addItem:item node:node.nextNode];
}
}
@end
复制代码
定义协议IteratorProtocol
@protocol IteratorProtocol <NSObject>
// 下一个元素
- (id)nextObject;
@end
复制代码
定义迭代器类LinkedListIterator
@interface LinkedListIterator : NSObject<IteratorProtocol>
+ (instancetype)linkedListIteratorWithLinkedList:(LinkedList *)linkedList;
@end
@interface LinkedListIterator ()
@property (nonatomic, strong) LinkedList *linkedList;
@property (nonatomic, strong) Node *currentNode;
@end
@implementation LinkedListIterator
+ (instancetype)linkedListIteratorWithLinkedList:(LinkedList *)linkedList {
LinkedListIterator *iterator = [[LinkedListIterator alloc] init];
iterator.linkedList = linkedList;
return iterator;
}
- (id)nextObject {
if (!self.currentNode) {
self.currentNode = self.linkedList.firstNode;
} else {
self.currentNode = self.currentNode.nextNode;
}
return self.currentNode;
}
@end
复制代码
控制器实现
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 系统迭代器
NSArray *arr = @[@"A", @"B", @"C", @"D"];
NSEnumerator *enumerator = [arr objectEnumerator];
NSString *obj = nil;
while ((obj = enumerator.nextObject)) {
NSLog(@"%@", obj);
}
NSLog(@"------------------------------------");
LinkedList *list = [[LinkedList alloc] init];
[list addItem:@"A"];
[list addItem:@"B"];
[list addItem:@"C"];
[list addItem:@"D"];
LinkedListIterator *iterator = [LinkedListIterator linkedListIteratorWithLinkedList:list];
Node *node;
while ((node = iterator.nextObject)) {
NSLog(@"%@", node.nodeName);
}
}
@end
复制代码
结果展现
2019-04-07 23:00:13.950111+0800 IteratorPattern[10885:90208] A
2019-04-07 23:00:13.950321+0800 IteratorPattern[10885:90208] B
2019-04-07 23:00:13.950442+0800 IteratorPattern[10885:90208] C
2019-04-07 23:00:13.950584+0800 IteratorPattern[10885:90208] D
2019-04-07 23:00:13.950706+0800 IteratorPattern[10885:90208] ------------------------------------
2019-04-07 23:00:13.950840+0800 IteratorPattern[10885:90208] A
2019-04-07 23:00:13.951111+0800 IteratorPattern[10885:90208] B
2019-04-07 23:00:13.951952+0800 IteratorPattern[10885:90208] C
2019-04-07 23:00:13.953016+0800 IteratorPattern[10885:90208] D
复制代码
苹果公司用本身的命名规则"枚举器/枚举"改写了迭代器模式,用于相关基础类的各类方法.
基础框架中的NSEnumerator
类实现了迭代器模式. NSArray
、NSSet
、NSDictionary
这样的集合类,定义了返回与集合的类型相应的NSEnumerator
子类实例的方法.
迭代器模式与访问者模式有些相似,尤为是把遍历算法放到访问者模式中或者在遍历聚合体时让内部迭代器对元素执行操做的时候.组合模式经常依靠迭代器来遍历其递归结构.多态的迭代器依靠工厂方法来实例化适当的迭代器具体子类.
表示一个做用于某个对象结构中的各元素的操做.它让咱们能够在不改变各元素的类的前提下定义做用于这些元素的新操做.
协议类Mark
// 不论线条仍是点,其实都是在介质上留下的标志(Mark),它为全部具体类定义了属性和方法
@protocol Mark <NSObject>
@property (nonatomic, assign) CGPoint location;
@property (nonatomic, assign) CGSize size;
@property (nonatomic, strong) id<Mark> lastChild;
- (void)addMark:(id<Mark>)mark;
- (void)removeMark:(id<Mark>)mark;
- (void)acceptMarkVisitor:(id<MarkVisitor>)visitor;
@end
复制代码
组件类点Dot
// 点,组件只有一个点,那么它会表现为一个实心圆,在屏幕上表明一个点
@interface Dot : NSObject<Mark>
@end
@implementation Dot
@synthesize location;
@synthesize lastChild;
@synthesize size;
- (void)addMark:(id<Mark>)mark {}
- (void)removeMark:(id<Mark>)mark {}
- (id<Mark>)lastChild {
return nil;
}
- (void)acceptMarkVisitor:(id<MarkVisitor>)visitor {
[visitor visitDot:self];
}
@end
复制代码
组件类顶点Vertex
// 顶点,链接起来的一串顶点,被绘制成链接起来的线条
@interface Vertex : NSObject<Mark>
@end
@implementation Vertex
@synthesize location;
@synthesize lastChild;
@synthesize size;
- (void)addMark:(id<Mark>)mark {}
- (void)removeMark:(id<Mark>)mark {}
- (id<Mark>)lastChild {
return nil;
}
- (void)acceptMarkVisitor:(id<MarkVisitor>)visitor {
[visitor visitVertex:self];
}
@end
复制代码
组件类线条Stroke
@interface Stroke ()
@property (nonatomic, strong) NSMutableArray<id<Mark>> *children;
@end
@implementation Stroke
@dynamic location;
- (instancetype)init {
if (self = [super init]) {
_children = [[NSMutableArray alloc] init];
}
return self;
}
- (void)addMark:(id<Mark>)mark {
[_children addObject:mark];
}
- (void)removeMark:(id<Mark>)mark {
[_children removeObject:mark];
}
- (void)setLocation:(CGPoint)location {
}
- (CGPoint)location {
if (_children.count == 0) {
return CGPointZero;
} else {
return self.children.firstObject.location;
}
}
- (id<Mark>)lastChild {
return _children.lastObject;
}
- (void)acceptMarkVisitor:(id<MarkVisitor>)visitor {
for (id<Mark> dot in self.children) {
[dot acceptMarkVisitor:visitor];
}
[visitor visitStroke:self];
}
@end
复制代码
定义访问者接口类MarkVisitor
// 访问者接口
@protocol MarkVisitor <NSObject>
- (void)visitMark:(id<Mark>)mark;
- (void)visitVertex:(Vertex *)vertex;
- (void)visitDot:(Dot *)dot;
- (void)visitStroke:(Stroke *)stroke;
@end
复制代码
定义绘制类MarkRenderer
// 具体的访问者,MarkRenderer绘制访问者,它是对这些点和先进行绘制操做的
@interface MarkRenderer : NSObject<MarkVisitor>
- (instancetype)initWithCGContext:(CGContextRef)context;
@end
@interface MarkRenderer ()
@property (nonatomic, assign) CGContextRef context;
@property (nonatomic, assign) BOOL shouldMoveContextToDot;
@end
@implementation MarkRenderer
- (instancetype)initWithCGContext:(CGContextRef)context {
if (self = [super init]) {
self.context = context;
self.shouldMoveContextToDot = YES;
}
return self;
}
- (void)visitMark:(id<Mark>)mark {
}
- (void)visitVertex:(Vertex *)vertex {
CGFloat x = vertex.location.x;
CGFloat y = vertex.location.y;
if (self.shouldMoveContextToDot) {
CGContextMoveToPoint(self.context, x, y);
self.shouldMoveContextToDot = NO;
} else {
CGContextAddLineToPoint(self.context, x, y);
}
}
- (void)visitDot:(Dot *)dot {
CGFloat x = dot.location.x;
CGFloat y = dot.location.y;
CGRect frame = CGRectMake(x, y, 2, 2);
CGContextSetFillColorWithColor(self.context, [[UIColor blackColor] CGColor]);
CGContextFillEllipseInRect(self.context, frame);
}
- (void)visitStroke:(Stroke *)stroke {
CGContextSetStrokeColorWithColor(self.context, [UIColor blueColor].CGColor);
CGContextSetLineWidth(self.context, 1);
CGContextSetLineCap(self.context, kCGLineCapRound);
CGContextStrokePath(self.context);
self.shouldMoveContextToDot = YES;
}
@end
复制代码
定义用于展现的视图CanvasView
@interface CanvasView : UIView
@property (nonatomic, strong) id<Mark> mark;
@end
@implementation CanvasView
- (void)setMark:(id<Mark>)mark {
_mark = mark;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
MarkRenderer *markRender = [[MarkRenderer alloc] initWithCGContext:context];
[self.mark acceptMarkVisitor:markRender];
}
@end
复制代码
控制器实现
@interface ViewController ()
@property (nonatomic, strong) id<Mark> parentMark;
@property (nonatomic, strong) CanvasView *canvasView;
@property (nonatomic, assign) CGPoint startPoint;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.parentMark = [[Stroke alloc] init];
[self setupView];
}
- (void)setupView
{
CanvasView *canvasView = [[CanvasView alloc] initWithFrame:self.view.frame];
canvasView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:canvasView];
self.canvasView = canvasView;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.startPoint = [[touches anyObject] locationInView:self.canvasView];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
CGPoint lastPoint = [[touches anyObject] previousLocationInView:self.canvasView];
if (CGPointEqualToPoint(lastPoint, self.startPoint)) {
id <Mark> newStroke = [[Stroke alloc] init];
[self addMark:newStroke shouldAddToPreviousMark:NO];
}
CGPoint currentPoint = [[touches anyObject] locationInView:self.canvasView];
Vertex *vertex = [[Vertex alloc] init];
vertex.location = currentPoint;
[self addMark:vertex shouldAddToPreviousMark:vertex];
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
CGPoint lastPoint = [[touches anyObject] previousLocationInView:self.canvasView];
CGPoint currentPoint = [[touches anyObject] locationInView:self.canvasView];
if (CGPointEqualToPoint(lastPoint, currentPoint))
{
Dot *singleDot = [[Dot alloc] init];
singleDot.location = currentPoint;
[self addMark:singleDot shouldAddToPreviousMark:NO];
}
self.startPoint = CGPointZero;
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.startPoint = CGPointZero;
}
- (void)addMark:(id<Mark>)mark shouldAddToPreviousMark:(BOOL)shouldAddToPreviousMark
{
if (shouldAddToPreviousMark) {
[self.parentMark.lastChild addMark:mark];
} else {
[self.parentMark addMark:mark];
}
self.canvasView.mark = self.parentMark;
}
@end
复制代码
访问者模式是扩展组合结构功能的一种强有力的方式.若是组合结构具备精心设计的基本操做,并且结构未来也不会变动,就可使用访问者模式,用各类不一样用途的访问者,以一样的方式访问这个组合结构.访问者模式用尽量少的修改,能够把组合结构与其余访问者类中的相关算法分离.
普通实现
设置协议的抽象(咱们想让全部的ImageComponent
都能支持UIImage
的重画方法)
@protocol ImageComponent <NSObject>
@optional
- (void)drawAtPoint:(CGPoint)point;
- (void)drawAtPoint:(CGPoint)point blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha;
- (void)drawInRect:(CGRect)rect;
- (void)drawInRect:(CGRect)rect blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha;
- (void)drawAsPatternInRect:(CGRect)rect;
@end
复制代码
设置核心的装饰类,也是滤镜基类
@interface ImageFilter : NSObject <ImageComponent>
{
@private
id <ImageComponent> component_;
}
/// 保持一个ImageComponent的引用,这个引用会被其余具体的装饰器装饰.
@property (nonatomic, strong) id<ImageComponent> component;
- (void)apply;
- (id)initWithImageComponent:(id<ImageComponent>)component;
- (id)forwardingTargetForSelector:(SEL)aSelector;
复制代码
- (id)initWithImageComponent:(id<ImageComponent>)component {
if (self = [super init]) {
[self setComponent:component];
}
return self;
}
- (void)apply {
// 应该由子类重载,应用真正的滤镜
}
/// 截获消息
- (id)forwardingTargetForSelector:(SEL)aSelector {
NSString *selectorName = NSStringFromSelector(aSelector);
if ([selectorName hasPrefix:@"draw"]) {
[self apply];
}
return component_;
}
复制代码
设置仿射变换滤镜
- (instancetype)initWithImageComponent:(id<ImageComponent>)component
transform:(CGAffineTransform)transform {
if (self = [super initWithImageComponent:component]) {
[self setTransform:transform];
}
return self;
}
- (void)apply {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextConcatCTM(context, transform_);
}
复制代码
设置阴影滤镜
- (void)apply {
CGContextRef context = UIGraphicsGetCurrentContext();
CGSize offset = CGSizeMake(-25, 15);
CGContextSetShadow(context, offset, 20.0);
}
复制代码
视图展现配置
- (void)setImage:(UIImage *)image {
image_ = image;
}
- (void)drawRect:(CGRect)rect {
[image_ drawInRect:rect];
}
复制代码
控制器配置
UIImage *img = [UIImage imageNamed:@"13.jpeg"];
CGAffineTransform rotateTransform = CGAffineTransformMakeRotation(-M_PI / 4.0);
CGAffineTransform translateTransform = CGAffineTransformMakeTranslation(-img.size.width / 2.0, img.size.height / 8.0);
CGAffineTransform finalTransform = CGAffineTransformConcat(rotateTransform, translateTransform);
id<ImageComponent>transformedImage = [[ImageTransformFilter alloc] initWithImageComponent:img transform:finalTransform];
id<ImageComponent>finalImage = [[ImageShadowFilter alloc] initWithImageComponent:transformedImage];
DecoratorView *decoratorView = [[DecoratorView alloc] initWithFrame:self.view.bounds];
[decoratorView setImage:(UIImage *)finalImage];
[self.view addSubview:decoratorView];
复制代码
设置基础滤镜配置方法
@interface UIImage (BaseFilter)
- (CGContextRef)beginContext;
- (UIImage *)getImageFromCurrentImageContext;
- (void)endContext;
@end
复制代码
@implementation UIImage (BaseFilter)
- (CGContextRef)beginContext {
CGSize size = [self size];
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
return context;
}
- (UIImage *)getImageFromCurrentImageContext {
[self drawAtPoint:CGPointZero];
UIImage *imageOut = UIGraphicsGetImageFromCurrentImageContext();
return imageOut;
}
- (void)endContext {
UIGraphicsEndImageContext();
}
@end
复制代码
设置仿射变换滤镜方法
@implementation UIImage (Transform)
- (UIImage *)imageWithTransform:(CGAffineTransform)transform {
CGContextRef context = [self beginContext];
CGContextConcatCTM(context, transform);
UIImage *imageOut = [self getImageFromCurrentImageContext];
[self endContext];
return imageOut;
}
@end
复制代码
设置阴影滤镜方法
@implementation UIImage (Shadow)
- (UIImage *)imageWithDropShadow {
CGContextRef context = [self beginContext];
CGSize offset = CGSizeMake(-25, 15);
CGContextSetShadow(context, offset, 20.0);
UIImage *imageOut = [self getImageFromCurrentImageContext];
[self endContext];
return imageOut;
}
@end
复制代码
控制器配置
- (void)viewDidLoad {
[super viewDidLoad];
UIImage *img = [UIImage imageNamed:@"13.jpeg"];
CGAffineTransform rotateTransform = CGAffineTransformMakeRotation(-M_PI / 4.0);
CGAffineTransform translateTransform = CGAffineTransformMakeTranslation(-img.size.width / 2.0, img.size.height / 8.0);
CGAffineTransform finalTransform = CGAffineTransformConcat(rotateTransform, translateTransform);
UIImage *transformedImage = [img imageWithTransform:finalTransform];
UIImage *finalImage = [transformedImage imageWithDropShadow];
DecoratorView *decoratorView = [[DecoratorView alloc] initWithFrame:self.view.bounds];
[decoratorView setImage:(UIImage *)finalImage];
[self.view addSubview:decoratorView];
}
复制代码
优势:
装饰模式在OC中会有不一样的实现方式即为范畴.真正子类方式的实际使用是一种较为结构化的方式链接各类装饰器.范畴的方式更为简单和轻量,适用于现有类只须要少许装饰器的应用程序.
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间发生耦合.此模式将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止.
责任链类图
请求处理典型结构图
接口处理请求的协议ChainOfResponsibilityProtocol
@protocol ChainOfResponsibilityProtocol <NSObject>
@property (nonatomic, strong) id<ChainOfResponsibilityProtocol> successor;
- (void)handlerRequest:(id)request;
@end
复制代码
定义链头类HeadChain
/// 链头
@interface HeadChain : NSObject<ChainOfResponsibilityProtocol>
@end
@interface HeadChain ()
@property (nonatomic, weak) id<ChainOfResponsibilityProtocol> nextSuccessor;
@end
@implementation HeadChain
@synthesize successor;
- (void)setSuccessor:(id<ChainOfResponsibilityProtocol>)successor {
self.nextSuccessor = successor;
}
- (id<ChainOfResponsibilityProtocol>)successor {
return self.nextSuccessor;
}
- (void)handlerRequest:(id)request {
[self.successor handlerRequest:request];
}
@end
复制代码
定义验证手机号码节点类PhoneNumChain
/// 验证手机号码节点
@interface PhoneNumChain : NSObject<ChainOfResponsibilityProtocol>
@end
@interface PhoneNumChain ()
@property (nonatomic, weak) id<ChainOfResponsibilityProtocol> nextSuccessor;
@end
@implementation PhoneNumChain
@synthesize successor;
- (void)setSuccessor:(id<ChainOfResponsibilityProtocol>)successor {
self.nextSuccessor = successor;
}
- (id<ChainOfResponsibilityProtocol>)successor {
return self.nextSuccessor;
}
- (void)handlerRequest:(id)request {
NSString *str = request;
if ([str isKindOfClass:[NSString class]] && str.length > 0) {
// 匹配电话号码(手机号以13, 15,18开头,八个 \d 数字字符)
BOOL isMatch = [str isMatch:RX(@"^((13[0-9])|(15[^4,\\D])|(18[0,0-9]))\\d{8}$")];
if (isMatch) {
NSLog(@"%@ is a PhoneNum", str);
} else {
[self.successor handlerRequest:request];
}
} else {
[self.successor handlerRequest:request];
}
}
@end
复制代码
验证邮箱节点类EmailChain
/// 验证邮箱节点
@interface EmailChain : NSObject<ChainOfResponsibilityProtocol>
@end
@interface EmailChain ()
@property (nonatomic, weak) id<ChainOfResponsibilityProtocol> nextSuccessor;
@end
@implementation EmailChain
@synthesize successor;
- (void)setSuccessor:(id<ChainOfResponsibilityProtocol>)successor {
self.nextSuccessor = successor;
}
- (id<ChainOfResponsibilityProtocol>)successor {
return self.nextSuccessor;
}
- (void)handlerRequest:(id)request {
NSString *str = request;
if ([str isKindOfClass:[NSString class]] && str.length > 0) {
// 匹配邮箱
BOOL isMatch = [str isMatch:RX(@"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}")];
if (isMatch) {
NSLog(@"%@ is a Email", str);
} else {
[self.successor handlerRequest:request];
}
} else {
[self.successor handlerRequest:request];
}
}
@end
复制代码
验证用户名节点类UserNameChain
/// 验证用户名节点
@interface UserNameChain : NSObject<ChainOfResponsibilityProtocol>
@end
@interface UserNameChain ()
@property (nonatomic, weak) id<ChainOfResponsibilityProtocol> nextSuccessor;
@end
@implementation UserNameChain
@synthesize successor;
- (void)setSuccessor:(id<ChainOfResponsibilityProtocol>)successor {
self.nextSuccessor = successor;
}
- (id<ChainOfResponsibilityProtocol>)successor {
return self.nextSuccessor;
}
- (void)handlerRequest:(id)request {
NSString *str = request;
if ([str isKindOfClass:[NSString class]] && str.length > 0) {
// 匹配用户名(用户名长度为6-20位之间,大小写字母或者数字都可)
BOOL isMatch = [str isMatch:RX(@"^[A-Za-z0-9]{6,20}+$")];
if (isMatch) {
NSLog(@"%@ is a UserName", str);
} else {
[self.successor handlerRequest:request];
}
} else {
[self.successor handlerRequest:request];
}
}
@end
复制代码
链尾类EndChain
/// 链尾
@interface EndChain : NSObject<ChainOfResponsibilityProtocol>
@end
@interface EndChain ()
@property (nonatomic, weak) id<ChainOfResponsibilityProtocol> nextSuccessor;
@end
@implementation EndChain
@synthesize successor;
- (void)setSuccessor:(id<ChainOfResponsibilityProtocol>)successor {
}
- (id<ChainOfResponsibilityProtocol>)successor {
return self;
}
- (void)handlerRequest:(id)request {
NSLog(@"没法处理该请求");
}
@end
复制代码
控制器实现
// 设置各请求链条
HeadChain *headChain = [[HeadChain alloc] init];
PhoneNumChain *phoneNumChain = [[PhoneNumChain alloc] init];
EmailChain *emailChain = [[EmailChain alloc] init];
UserNameChain *userNameChain = [[UserNameChain alloc] init];
EndChain *endChain = [[EndChain alloc] init];
// 设置下一连接点
headChain.successor = phoneNumChain;
phoneNumChain.successor = emailChain;
emailChain.successor = userNameChain;
userNameChain.successor = endChain;
// 处理事件
[headChain handlerRequest:@"18659007343"];
[headChain handlerRequest:@"18659007343@qq.com"];
[headChain handlerRequest:@"abc1865900"];
[headChain handlerRequest:@"====="];
复制代码
结果展现
2019-04-17 00:26:21.661847+0800 ChainOfResponsibilityPattern[84339:1697824] 18659007343 is a PhoneNum
2019-04-17 00:26:21.662235+0800 ChainOfResponsibilityPattern[84339:1697824] 18659007343@qq.com is a Email
2019-04-17 00:26:21.662562+0800 ChainOfResponsibilityPattern[84339:1697824] abc1865900 is a UserName
2019-04-17 00:26:21.662889+0800 ChainOfResponsibilityPattern[84339:1697824] 没法处理该请求
复制代码
在Cocoa
中UIResponder
类就是责任链的一个实例.当操做应用时,进行点击,点击操做经过责任链一步步走下去直到找到相对应要响应的UIResponder
.
定义一个操做中算法的骨架,而将一些步骤延迟到子类中.模板方法使子类能够冲定义算法的某些特定步骤而不改变该算法的结构.
定义基础类AnySandwich
@interface AnySandwich : NSObject
- (void)make;
- (void)prepareBread;
- (void)putBreadOnPlate;
- (void)addMeat;
- (void)addCondiments;
- (void)serve;
- (void)extraStep;
@end
复制代码
内部实现制做三明治的基本流程. extraStep
为钩子方法,子类可实现也能够不用实现. prepareBread
addMeat
addCondiments
的具体实现交由子类.如若没有实现,将libc++abi.dylib: terminating with uncaught exception of type NSException
运行失败来限制子类.
@implementation AnySandwich
- (void)make {
[self prepareBread];
[self putBreadOnPlate];
[self addMeat];
[self addCondiments];
[self serve];
[self extraStep];
}
- (void)putBreadOnPlate {
// 作任何三明治都要先把面包放在盘子上
}
- (void)serve {
// 任何三明治作好了都要上餐
}
#pragma mark -
#pragma Detail 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)];
}
@end
复制代码
ReubenSandwich
实现
@implementation ReubenSandwich
- (void)prepareBread {
[self cutRyeBread];
}
- (void)addMeat {
[self addCornBeef];
}
- (void)addCondiments {
[self addSauerkraut];
[self addThousandIslandDressing];
[self addSwissCheese];
}
- (void)extraStep {
[self grillIt];
}
#pragma mark -
#pragma mark ReubenSandwich Specific Methods
- (void)cutRyeBread {
// 鲁宾三明治须要两片黑麦面包
}
- (void)addCornBeef {
// 鲁宾三明治加大量腌牛肉
}
- (void)addSauerkraut {
// 加入德国酸菜
}
- (void)addThousandIslandDressing {
// 加入千岛酱
}
- (void)addSwissCheese {
// 加入上等瑞士奶酪
}
- (void)grillIt {
// 最后要把它烤一下
}
@end
复制代码
模板方法是代码复用的基本技术,是抽出共同行为放入框架类中的手段.这一方式有助于提升可扩展性与可复用性,而维持各类类之间的松耦合.
建立算法抽象基类,开放验证接口并实现
@interface StringValidator : NSObject
- (BOOL)validateString:(NSString *)str error:(NSError **)error;
@end
@implementation StringValidator
- (BOOL)validateString:(NSString *)str error:(NSError * _Nullable __autoreleasing *)error {
if (error) {
*error = nil;
}
return NO;
}
@end
复制代码
建立相关的算法继承类 NumbericValidator
数值判断类
@interface NumbericValidator : StringValidator
- (BOOL)validateString:(NSString *)str error:(NSError * _Nullable __autoreleasing *)error;
@end
@implementation NumbericValidator
- (BOOL)validateString:(NSString *)str error:(NSError *__autoreleasing _Nullable *)error {
NSError *regError = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[0-9]*$" options:NSRegularExpressionAnchorsMatchLines error:®Error];
NSUInteger numberOfMatchs = [regex numberOfMatchesInString:str options:NSMatchingAnchored range:NSMakeRange(0, str.length)];
if (numberOfMatchs == 0) {
if (error != nil) {
NSString *description = NSLocalizedString(@"Failed", @"");
NSString *reason = NSLocalizedString(@"can contain only numberical", @"");
NSArray *objArray = [NSArray arrayWithObjects:description, reason, nil];
NSArray *keyArray = [NSArray arrayWithObjects:NSLocalizedDescriptionKey, NSLocalizedFailureReasonErrorKey, nil];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjects:objArray forKeys:keyArray];
*error = [NSError errorWithDomain:@"StringErrorDomain" code:1001 userInfo:userInfo];
}
return NO;
}
return YES;
}
@end
复制代码
AlphaValidator
字母判断类
@interface AlphaValidator : StringValidator
- (BOOL)validateString:(NSString *)str error:(NSError * _Nullable __autoreleasing *)error;
@end
@implementation AlphaValidator
- (BOOL)validateString:(NSString *)str error:(NSError *__autoreleasing _Nullable *)error {
NSError *regError = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[a-zA-Z]*$" options:NSRegularExpressionAnchorsMatchLines error:®Error];
NSUInteger numberOfMatchs = [regex numberOfMatchesInString:str options:NSMatchingAnchored range:NSMakeRange(0, str.length)];
if (numberOfMatchs == 0) {
if (error != nil) {
NSString *description = NSLocalizedString(@"Failed", @"");
NSString *reason = NSLocalizedString(@"can contain only alpha", @"");
NSArray *objArray = [NSArray arrayWithObjects:description, reason, nil];
NSArray *keyArray = [NSArray arrayWithObjects:NSLocalizedDescriptionKey, NSLocalizedFailureReasonErrorKey, nil];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjects:objArray forKeys:keyArray];
*error = [NSError errorWithDomain:@"StringErrorDomain" code:1002 userInfo:userInfo];
}
return NO;
}
return YES;
}
@end
复制代码
算法策略类StringValidatorManager
@interface StringValidatorManager : NSObject
+ (BOOL)numbervalidString:(NSString *)str error:(NSError **)error;
+ (BOOL)alphaString:(NSString *)str error:(NSError **)error;
@end
@implementation StringValidatorManager
+ (BOOL)numbervalidString:(NSString *)str error:(NSError * _Nullable __autoreleasing *)error {
NumbericValidator *number = [[NumbericValidator alloc] init];
return [number validateString:str error:error];
}
+ (BOOL)alphaString:(NSString *)str error:(NSError * _Nullable __autoreleasing *)error {
AlphaValidator *alpha = [[AlphaValidator alloc] init];
return [alpha validateString:str error:error];
}
@end
复制代码
控制器实现
NSString *test1 = @"112";
NSError *error0;
[StringValidatorManager numbervalidString:test1 error:&error0];
if (error0) {
NSLog(@"0: %@", error0.localizedFailureReason);
}
NSError *error1;
[StringValidatorManager alphaString:test1 error:&error1];
if (error1) {
NSLog(@"1: %@", error1.localizedFailureReason);
}
NSString *test2 = @"adsf";
NSError *error2;
[StringValidatorManager numbervalidString:test2 error:&error2];
if (error2) {
NSLog(@"2: %@", error2.localizedFailureReason);
}
NSError *error3;
[StringValidatorManager alphaString:test2 error:&error3];
if (error3) {
NSLog(@"3: %@", error3.localizedFailureReason);
}
复制代码
结果展现
2018-12-25 22:22:45.027745+0800 StrategyPattern[21641:845119] 1: can contain only alpha
2018-12-25 22:22:45.028076+0800 StrategyPattern[21641:845119] 2: can contain only numberical
复制代码
优势
策略模式与装饰模式有些类似.装饰器从外部扩展对象的行为,而各类策略则被封装在对象之中.因此说装饰器改变对象的"外表"而策略改变对象的"内容".
将请求封装成一个对象,从而可用不一样的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操做.
Client
建立ConcreteCommand
对象并设定器receiver
; Invoker
要求通用命令(其实是ConcreteCommand
)实施请求; Command
要为Invoker
所知的通用接口; ConcreteCommand
起Receiver
和对它的操做action
之间的中间人做用; Receiver
能够随着由Command
(ConcreteCommand
)对象实施的相应请求,而执行实际操做的任何对象.
接口协议CommandInterface
/// 命令对象的公共接口(按钮执行的动做)
@protocol CommandInterface <NSObject>
/// 执行命令
- (void)execute;
/// 撤销
- (void)undo;
@end
复制代码
定义灯类Light
/// 电灯类
@interface Light : NSObject
- (void)lightOn;
- (void)lightOff;
@end
@implementation Light
- (void)lightOn {
NSLog(@"开灯");
}
- (void)lightOff {
NSLog(@"关灯");
}
@end
复制代码
定义CD播放器类CDPlayer
/// CD播放器类
@interface CDPlayer : NSObject
- (void)CDPlayerOn;
- (void)CDPlayerOff;
@end
@implementation CDPlayer
- (void)CDPlayerOn {
NSLog(@"打开CD播放器");
}
- (void)CDPlayerOff {
NSLog(@"关闭CD播放器");
}
@end
复制代码
打开灯命令类LightOnCommand
/// 打开灯命令类
@interface LightOnCommand : NSObject<CommandInterface>
- (instancetype)initWithLight:(Light *)light;
@end
@implementation LightOnCommand
- (instancetype)initWithLight:(Light *)light {
if (self = [super init]) {
self.light = light;
}
return self;
}
- (void)execute {
[self.light lightOn];
}
- (void)undo {
[self.light lightOff];
}
@end
复制代码
关灯命令类LightOffCommand
/// 关灯命令类
@interface LightOffCommand : NSObject<CommandInterface>
- (instancetype)initWithLight:(Light *)light;
@end
@implementation LightOffCommand
- (instancetype)initWithLight:(Light *)light {
if (self = [super init]) {
self.light = light;
}
return self;
}
- (void)execute {
[self.light lightOff];
}
- (void)undo {
[self.light lightOn];
}
@end
复制代码
CD播放器播放类CDPlayerOnCommand
/// CD播放器播放类
@interface CDPlayerOnCommand : NSObject<CommandInterface>
- (instancetype)initWithCDPlayer:(CDPlayer *)cdPlayer;
@end
@implementation CDPlayerOnCommand
- (instancetype)initWithCDPlayer:(CDPlayer *)cdPlayer {
if (self = [super init]) {
self.cdPlayer = cdPlayer;
}
return self;
}
- (void)execute {
[self.cdPlayer CDPlayerOn];
}
- (void)undo {
[self.cdPlayer CDPlayerOff];
}
@end
复制代码
定义CD播放器关闭类CDPlayerOffCommand
/// CD播放器关闭类
@interface CDPlayerOffCommand : NSObject<CommandInterface>
- (instancetype)initWithCDPlayer:(CDPlayer *)cdPlayer;
@end
@implementation CDPlayerOffCommand
- (instancetype)initWithCDPlayer:(CDPlayer *)cdPlayer {
if (self = [super init]) {
self.cdPlayer = cdPlayer;
}
return self;
}
- (void)execute {
[self.cdPlayer CDPlayerOff];
}
- (void)undo {
[self.cdPlayer CDPlayerOn];
}
@end
复制代码
定义遥控器类RemoteControl
/// 命令调用者(遥控器)
@interface RemoteControl : NSObject
//@property (nonatomic, strong) id<CommandInterface> slot;
- (void)onClickWithIdx:(NSInteger)idx;
- (void)offClickWithIdx:(NSInteger)idx;
- (void)setCommandWithIdx:(NSInteger)idx
onCommand:(id<CommandInterface>)onCommand
offCommand:(id<CommandInterface>)offCommand;
/// 撤销刚才的操做
- (void)undoAction;
/// 撤销全部操做
- (void)undoAllAction;
@end
@interface RemoteControl ()
@property (nonatomic, strong) NSArray<id<CommandInterface>> *onCommands;
@property (nonatomic, strong) NSArray<id<CommandInterface>> *offCommands;
@property (nonatomic, strong) id<CommandInterface> undoCommand; ///< 上一次的命令
@property (nonatomic, strong) NSMutableArray<id<CommandInterface>> *completeCommandsArr;
@end
@implementation RemoteControl
- (instancetype)init {
if (self = [super init]) {
// 默认有4类命令类型
NSMutableArray *mOnArr = [[NSMutableArray alloc] init];
NSMutableArray *mOffArr = [[NSMutableArray alloc] init];
for (int i = 0; i < 4; ++i) {
[mOnArr addObject:[[DefaultCommand alloc] init]];
[mOffArr addObject:[[DefaultCommand alloc] init]];
}
self.onCommands = mOnArr.copy;
self.offCommands = mOnArr.copy;
self.completeCommandsArr = [[NSMutableArray alloc] init];
}
return self;
}
- (void)onClickWithIdx:(NSInteger)idx {
if (idx >= self.onCommands.count || idx < 0) {
return;
}
[self.onCommands[idx] execute];
self.undoCommand = self.onCommands[idx];
[self.completeCommandsArr addObject:self.onCommands[idx]];
}
- (void)offClickWithIdx:(NSInteger)idx {
if (idx >= self.offCommands.count || idx < 0) {
return;
}
[self.offCommands[idx] execute];
self.undoCommand = self.offCommands[idx];
[self.completeCommandsArr addObject:self.offCommands[idx]];
}
- (void)undoAction {
[self.undoCommand undo];
[self.completeCommandsArr removeObject:self.undoCommand];
}
- (void)undoAllAction {
[self.completeCommandsArr enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id<CommandInterface> _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[obj undo];
}];
[self.completeCommandsArr removeAllObjects];
}
- (void)setCommandWithIdx:(NSInteger)idx
onCommand:(id<CommandInterface>)onCommand
offCommand:(id<CommandInterface>)offCommand {
if (idx < 0 || idx >= self.onCommands.count) {
return;
}
if (idx < 0 || idx >= self.offCommands.count) {
return;
}
NSMutableArray *mOnCommands = [self.onCommands mutableCopy];
[mOnCommands replaceObjectAtIndex:idx withObject:onCommand];
self.onCommands = mOnCommands;
NSMutableArray *mOffCommands = [self.offCommands mutableCopy];
[mOffCommands replaceObjectAtIndex:idx withObject:offCommand];
self.offCommands = mOffCommands;
}
@end
复制代码
定义初始的命令类
/// 默认命令类(设备默认状态)
@interface DefaultCommand : NSObject<CommandInterface>
@end
@implementation DefaultCommand
- (void)execute {
NSLog(@"默认命令状态下");
}
- (void)undo {
NSLog(@"默认撤销");
}
@end
复制代码
定义面板用于提供给外接接口
/// 命令装配者(将命令安装到遥控器上)
@interface RemoteLoader : NSObject
@property (nonatomic, strong, readonly) RemoteControl *rc;
- (instancetype)initWithRemoteControl:(RemoteControl *)rc;
@end
@implementation RemoteLoader
- (instancetype)initWithRemoteControl:(RemoteControl *)rc {
if (self = [super init]) {
self.rc = rc;
[self configCommands];
}
return self;
}
- (void)configCommands {
Light *light = [[Light alloc] init];
LightOnCommand *lightOnCommand = [[LightOnCommand alloc] initWithLight:light];
LightOffCommand *lightOffCommand = [[LightOffCommand alloc] initWithLight:light];
[self.rc setCommandWithIdx:0 onCommand:lightOnCommand offCommand:lightOffCommand];
CDPlayer *cd = [[CDPlayer alloc] init];
CDPlayerOnCommand *cdPlayerOnCommand = [[CDPlayerOnCommand alloc] initWithCDPlayer:cd];
CDPlayerOffCommand *cdPlayerOffCommand = [[CDPlayerOffCommand alloc] initWithCDPlayer:cd];
[self.rc setCommandWithIdx:1 onCommand:cdPlayerOnCommand offCommand:cdPlayerOffCommand];
}
@end
复制代码
控制器实现
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
RemoteControl *rc = [[RemoteControl alloc] init];
RemoteLoader *loader = [[RemoteLoader alloc] initWithRemoteControl:rc];
[loader.rc onClickWithIdx:0];
[loader.rc onClickWithIdx:1];
[loader.rc offClickWithIdx:0];
[loader.rc offClickWithIdx:1];
NSLog(@"------------执行撤销动做------------");
[loader.rc undoAction];
[loader.rc undoAllAction];
}
@end
复制代码
结果展现
2019-04-14 21:54:05.762810+0800 CommandPattern[68418:1486836] 开灯
2019-04-14 21:54:05.762981+0800 CommandPattern[68418:1486836] 打开CD播放器
2019-04-14 21:54:05.763088+0800 CommandPattern[68418:1486836] 关灯
2019-04-14 21:54:05.763198+0800 CommandPattern[68418:1486836] 关闭CD播放器
2019-04-14 21:54:05.763315+0800 CommandPattern[68418:1486836] ------------执行撤销动做------------
2019-04-14 21:54:05.763417+0800 CommandPattern[68418:1486836] 打开CD播放器
2019-04-14 21:54:05.763661+0800 CommandPattern[68418:1486836] 开灯
2019-04-14 21:54:05.763770+0800 CommandPattern[68418:1486836] 关闭CD播放器
2019-04-14 21:54:05.763886+0800 CommandPattern[68418:1486836] 关灯
复制代码
Cocoa Touch框架中使用命令模式的典型例子.
运用共享技术有效地支持大量细粒度的对象.
花朵视图FlowerView
// 绘制一朵花朵图案
@interface FlowerView : UIImageView
@end
@implementation FlowerView
- (void)drawRect:(CGRect)rect {
[self.image drawInRect:rect];
}
@end
复制代码
花朵生成工厂类FlowerFactory
.
`FlowerFactory`用`flowerPool`聚合了一个花朵池的引用.
`flowerPool`是一个保存`FlowerView`的全部实例的数据结构.
`FlowerFactory`经过`flowerViewWithType:`方法返回`FlowerView`
实例.
复制代码
static NSInteger kTotalNumberOfFlowTypes = 7;
typedef NS_ENUM(NSInteger, FlowerType) {
kAnemone = 0,
kCosmos,
kGerberas,
kHollyhock,
kJasmine,
kZinnia
};
NS_ASSUME_NONNULL_BEGIN
@interface FlowerFactory : NSObject
- (UIView *)flowerViewWithType:(FlowerType)type;
@end
NS_ASSUME_NONNULL_END
@interface FlowerFactory ()
@property (nonatomic, strong) NSMutableDictionary *flowerPool;
@end
@implementation FlowerFactory
- (UIView *)flowerViewWithType:(FlowerType)type {
UIView *flowerView = [_flowerPool objectForKey:@(type)];
if (flowerView) {
return flowerView;
}
NSString *imgName;
switch (type) {
case kAnemone:
imgName = @"anemone";
break;
case kCosmos:
imgName = @"cosmos";
break;
case kGerberas:
imgName = @"gerberas";
break;
case kHollyhock:
imgName = @"hollyhock";
break;
case kJasmine:
imgName = @"jasmine";
break;
case kZinnia:
imgName = @"zinnia";
break;
default:
break;
}
UIImage *img = [UIImage imageNamed:imgName];
if (!img) {
return nil;
}
FlowerView *tmpView = [[FlowerView alloc] init];
tmpView.image = img;
[self.flowerPool setObject:tmpView forKey:@(type)];
return tmpView;
}
- (NSMutableDictionary *)flowerPool {
if (!_flowerPool) {
NSMutableDictionary *mDic = [[NSMutableDictionary alloc] initWithCapacity:kTotalNumberOfFlowTypes];
_flowerPool = mDic;
}
return _flowerPool;
}
@end
复制代码
花朵外部数据结构ExtrinsicFlowerState
#ifndef ExtrinsicFlowerState_h
#define ExtrinsicFlowerState_h
struct ExtrinsicFlowerState {
__unsafe_unretained UIView *flowerView;
CGRect area;
};
复制代码
花朵展现视图FlowerContainerView
@interface FlowerContainerView : UIView
@property (nonatomic, strong) NSArray *flowerList;
@end
@implementation FlowerContainerView
- (void)drawRect:(CGRect)rect {
for (NSValue *stateValue in self.flowerList) {
struct ExtrinsicFlowerState state;
[stateValue getValue:&state];
UIView *flowerView = state.flowerView;
CGRect frame = state.area;
[flowerView drawRect:frame];
}
}
@end
复制代码
控制器实现
static NSInteger kFlowerListCount = 200;
@interface ViewController ()
@property (nonatomic, strong) FlowerFactory *flowerFactory;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
FlowerContainerView *containerView = [[FlowerContainerView alloc] initWithFrame:self.view.bounds];
containerView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:containerView];
_flowerFactory = [[FlowerFactory alloc] init];
NSMutableArray *flowerList = [[NSMutableArray alloc] initWithCapacity:kFlowerListCount];
for (int i = 0; i < kFlowerListCount; ++i) {
// 从工厂取得一个共享的花朵享元对象实例
FlowerType type = arc4random() % kTotalNumberOfFlowTypes;
UIView *flowerView = [_flowerFactory flowerViewWithType:type];
// 设置花朵显示的区域
CGRect viewBounds = self.view.bounds;
CGFloat x = arc4random() % (int)CGRectGetWidth(viewBounds);
CGFloat y = arc4random() % (int)CGRectGetHeight(viewBounds);
CGFloat minSize = 10;
CGFloat maxSize = 60;
CGFloat size = (arc4random() % (int)(maxSize - minSize)) + minSize;
struct ExtrinsicFlowerState state;
state.flowerView = flowerView;
state.area = CGRectMake(x, y, size, size);
[flowerList addObject:[NSValue value:&state withObjCType:@encode(struct ExtrinsicFlowerState)]];
}
[containerView setFlowerList:flowerList.copy];
}
@end
复制代码
经过享元对象可以节省的空间,取决于几个因素:
然而,对共享对象外在状态的传递、查找和计算,可能产生运行时的开销,尤为在外在状态本来是做为内在状态来保存的时候.当享元的共享愈来愈多时,空间的节省会抵消这些开销.共享的享元越多,节省的存储就越多.节省直接跟共享的状态相关.若是对象有大量内在和外在状态,外在状态又可以计算出来而不用存储的时候,就能节省最大的空间.这样咱们以两种方式节省了存储空间:共享减小了内在状态的开销,经过牺牲计算时间又节省了外在状态的存储空间.
为其余对象提供一种代理以控制对这个对象的访问.
定义代理类SendGift
@protocol SendGift <NSObject>
- (void)sendGift;
@end
复制代码
哆啦A梦
@interface Doraemon : NSObject<SendGift>
@end
复制代码
雇主类
@interface Person : NSObject
@property (nonatomic, weak) id<SendGift> delegate;
@end
复制代码
调用场景
Person *daxiong = [[Person alloc] init];
Doraemon *doraemon = [[Doraemon alloc] init];
// 哆啦A梦成为代理,替大熊送礼物
daxiong.delegate = doraemon;
[daxiong.delegate sendGift];
复制代码
主要思想是使用一个基本上跟实体对象行为相同的代理.客户端能够"透明地"使用代理,即没必要知悉所面对的只是一个代理而不是实体对象.当客户端请求某些建立的开销较大的功能时,代理将把请求转发给实体对象,准备好请求的功能并返回给客户端.客户端不知道幕后发生了什么.
代理模式在OC中会经常会出现而且平常开发也会用到,最为典型的例子就是Applegate
类了,它被委托处理应用生命周期期间所面对的各类情况.
在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象以外保存这个状态.这样之后就可将对象恢复到原先保存的状态.
定义原发器类Originator
@interface Originator : NSObject
@property (nonatomic, copy) NSString *address;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
- (Memento *)createMemento;
- (void)setMemento:(Memento *)memento;
@end
@implementation Originator
- (Memento *)createMemento {
Memento *memo = [[Memento alloc] init];
memo.age = self.age;
memo.name = self.name;
return memo;
}
- (void)setMemento:(Memento *)memento {
self.age = memento.age;
self.name = memento.name;
}
- (NSString *)description {
return [NSString stringWithFormat:@"name = %@, age = %ld", self.name, self.age];
}
@end
复制代码
定义备忘录类Memento
@interface Memento : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end
复制代码
定义看管者类Caretaker
@interface Caretaker : NSObject
- (void)archiveMemento:(Memento *)memento;
- (Memento *)getMemento;
@end
@interface Caretaker ()
@property (nonatomic, strong) Memento *memento;
@end
@implementation Caretaker
- (void)archiveMemento:(Memento *)memento {
self.memento = memento;
}
- (Memento *)getMemento {
return self.memento;
}
@end
复制代码
控制器实现
@implementation ViewController
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Originator *oriAtor = [[Originator alloc] init];
oriAtor.name = @"sansa";
oriAtor.age = 18;
NSLog(@"1 --- %@", oriAtor);
// 保存十八岁的样子
Caretaker *taker = [[Caretaker alloc] init];
[taker archiveMemento:[oriAtor createMemento]];
// 过了好多年
oriAtor.age = 78;
NSLog(@"2 --- %@", oriAtor);
// 吃了药剂,重返十八岁
[oriAtor setMemento:[taker getMemento]];
NSLog(@"3 --- %@", oriAtor);
}
@end
/* MementoPattern[38016:1796366] 1 --- name = sansa, age = 18
** MementoPattern[38016:1796366] 2 --- name = sansa, age = 78
** MementoPattern[38016:1796366] 3 --- name = sansa, age = 18
*/
复制代码
**Cocoa Touch
框架在归档、属性列表序列化和核心数据中采用了备忘录模式.
设计模式是一套被反复使用的、多数人知晓的、通过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石同样。项目中合理地运用设计模式能够完美地解决不少问题,每种模式在现实中都有相应的原理来与之对应,每种模式都描述了一个在咱们周围不断重复发生的问题,以及该问题的核心解决方案,这也是设计模式能被普遍应用的缘由。
无论是什么开发都会用到设计模式,学习好设计模式对咱们对编码架构设计会有一个很好的提高.固然这也是会有至关大对学习成本,学习了理论后更须要去实践,Talk is cheap. Show me the code.
理论和实践结合这样才会有更好的理解.
最后引用乔帮主的话Stay hungry Stay foolish
共勉.
gitHub: PatternDemos