您的位置:首页 > 其它

设计模式--原型/外观(OC 实例)

2016-06-23 22:06 543 查看
1.原型设计模式

首先从简单的入手。看看原型模式吧。学习Javascript的时候有一个ProtoType 翻译过来就是原型,那么什么是原型呢?

举个生活中的例子,假设你要做生意 要发名片 那么 你就需要先设计一个名片然后打印N多份然后发送给客户。即copy。

在编程语言当中,经常有这样的情况,如我想操作某个对象,但是我又不想把他的内容改变了,这时候需要先保存这个对象。或者是我需要多个一样的对象。

1.1 代码设计

以Person类为例

[objc] view
plain copy

print?

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic,copy) NSString * name;

@property (nonatomic,copy) NSString * sex;

@property (nonatomic,copy) NSString * experience;

//显示

-(void)display;

-(void)test1;

-(void)test2;

@end

@implementation Person

-(void)display

{

NSLog(@"姓名:%@",_name);

NSLog(@"性别:%@",_sex);

NSLog(@"工作经验%@",_experience);

}

@end


以上代码 在main函数中如果需要再创建一个,那么需要多次alloc init

[objc] view
plain copy

print?

Person * p = [[Person alloc]init];

p.name = @"name1";

p.sex = @"男";

p.experience = @"一年";

[p display];

Person * p1 = [[Person alloc]init];

p1.name = @"name1";

p1.sex = @"男";

p1.experience = @"一年";

[p1 display];




创建的过程是一个耗费cpu的过程 想象一下 足够大的数据量下都进行创建 系统性能会如何呢?而且如果对变量设置 基本上都是一样代码 造成代码冗余。

于是原型设计模式就很有必要了。

1.2 对代码进行重构

[objc] view
plain copy

print?

@interface Person : NSObject

@property (nonatomic,copy) NSString * name;

@property (nonatomic,copy) NSString * sex;

@property (nonatomic,copy) NSString * experience;

//提供原型类的克隆接口

-(instancetype)clone;

//显示

-(void)display;

@end

@implementation Person

-(void)display

{

NSLog(@"姓名:%@",_name);

NSLog(@"性别:%@",_sex);

NSLog(@"工作经验%@",_experience);

}

-(instancetype)clone

{

return [self copy]; (1)标记

}



[objc] view
plain copy

print?

-(id)copyWithZone:(NSZone *)zone

{

Prototype * p = [[[self class] alloc]init];

p.name = self.name;

return p;

}

@end


[objc] view
plain copy

print?

为什么要写下面这个方法呢

[objc] view
plain copy

print?

答案: 以上代码中红色标记位置,是调用该类的copy方法,这个方法是从NSObject继承而来,而这个方法内部会调用copyWithZone方法,这个方法是NSCopying协议里面的,对于任何继承自NSObject的类而言,如果需要使用copy mutablecopy 则需要重载copyWithZone方法或者mutableCopyWithZone方法。

[objc] view
plain copy

print?

系统类之所以需要不需要重写这两个方法,是因为内部已经重载了。



1.3 什么是原型设计模式
原型设计模式:用原型实例指定创建对象的种类 并通过拷贝这个对象来得到新的对象

其类图如下:



从上面可以看到 当前一个原型的类中提供一个用于复制的接口 使用这个类创建出实例后,每个实例都有一个clone的接口 于是用这个实例就可以拷贝出新的对象。

1.4 iOS中的原型设计模式

iOS中已经实现了原型设计模式,提供了用于复制的接口。由于iOS不支持接口,将拷贝的接口做成了协议。NSCopying。

看系统内部NSCopying 的声明:

@protocol NSCopying

[objc] view
plain copy

print?

- (id)copyWithZone:(NSZone *)zone;

@end

如果需要用到拷贝 必须遵守这个协议 在类内实现copyWithZone方法。

但是 有没有发现,fundation中的好多对象都已经遵守了 而且还多了一个NSMutableCopying。这个暂时不讨论,只讨论NSCopying。

1.5 iOS中原型设计模式的使用情形:

需要创建的对象应独立于其类型和创建方式

要实例化的类是在运行时决定的

不想要与产品层次相对应的工厂层次 (不太懂)

不同类的实例间的差异仅仅是状态的若干组合 因此复制相应数量的原型比手工实例化更方便。

该模式的最低限度是生成对象的真实副本 以用作同一环境下其他相关事物的基础

那么现在应该清楚iOS中的NSCopying 和NSMutableCopying是运用的原型设计模式。那么我们来讨论下。

首先,涉及到深拷贝和浅拷贝的内容。

浅拷贝:如果当前拷贝只是复制了对象的指针,而没有内容的复制 被称为浅拷贝。如下图。



深拷贝:如果当前拷贝不仅仅复制了对象的指针,而且在内存开辟了内存空间,以存储拷贝的内容,被称之为深拷贝。如下图。



1.6 cocoa Touch框架中的对象复制

coucoa touch框架为NSObject派生类提供了两个协议。NSCopying NSMutableCopying。

以iOS中字符串的复制为例 讨论深拷贝和浅拷贝。

-(void)test1

[objc] view
plain copy

print?

{

NSString * str = @"abc";

NSLog(@"字符串地址%p",str);

NSString * str1 = [str copy];

NSLog(@"不可变字符串copy后地址%p",str1);

NSString * str2 = [str mutableCopy];

NSLog(@"不可变字符串mutableCopy后地址%p",str2);

NSMutableString * strM = [[NSMutableString alloc]initWithString:@"def"];

NSMutableString * strM1 = [strM copy];

[objc] view
plain copy

print?

NSLog(@"可变字符串copy后地址%p",strM1);

NSString * strM2 = [strM mutableCopy];

NSLog(@"可变字符串的mutablecopy地址%p",strM2);

}

[objc] view
plain copy

print?

console的信息:

[objc] view
plain copy

print?

2015-11-13 18:13:06.162 0-5 原型模式[2344:187326] 字符串地址0x1000020c0

[objc] view
plain copy

print?

2015-11-13 18:13:06.164 0-5 原型模式[2344:187326] 不可变字符串copy后地址0x1000020c0

2015-11-13 18:13:06.165 0-5 原型模式[2344:187326] 不可变字符串mutableCopy后地址0x1004046e0

2015-11-13 18:13:06.165 0-5 原型模式[2344:187326] 可变字符串copy后地址0x66656435

2015-11-13 18:13:06.165 0-5 原型模式[2344:187326] 可变字符串的mutablecopy地址0x1004048d0


由以上结果可以看出,NSString的copy得到的字符串地址相同,mutable copy后得到字符串地址不同,NSMutableString copy得到字符串地址不同,mutable copy得到字符串地址不同。

结论:NSString的copy是浅拷贝,而NSMutableString的copy mutable copy NSString的mutableCopy都是深拷贝

是否是深拷贝的唯一判定标准是:是否通过拷贝得到了新的对象,而非仅仅拷贝了地址。

下面讨论拷贝得到的字符串的可变性。

[objc] view
plain copy

print?

-(void)test2

{

//讨论字符串复制后的可变性

NSString * str = @"abc";

NSMutableString * str1 = [str copy];

NSMutableString * str2 = [str mutableCopy];

NSMutableString * strM = [[NSMutableString alloc]initWithString:@"abc"];

NSMutableString * strM1 = [strM copy];

NSMutableString * strM2 = [strM mutableCopy];

[str1 appendString:@"a"];//1

[str2 appendString:@"a"];//2

[strM1 appendString:@"a"];//3

[strM2 appendString:@"a"];//4

}

以上得到NSString NSMu table St ring的copy和mutableCopy字符串之后 分别用NSMutableString接收,然后操作该对象。

做标注的1,3处 会报错误如下

[objc] view
plain copy

print?

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSTaggedPointerString appendString:]: unrecognized selector sent to instance 0x63626135'

尝试将不可识别的消息发送给实例。

也就是说 1,3得到的字符串是不可变的。

结论:无论是NSString 还是NSMutable String 通过copy得到的字符串 都是不可变的。通过mutableCopy得到的字符串 都是可变的。

那么在oc中是仅仅是字符串是这样子的吗?

下面实例给出数组的测试用例

[objc] view
plain copy

print?

-(void)test3

{

NSArray * arr = @[@"2",@"1"];

NSMutableArray * arrM = [NSMutableArray arrayWithArray:arr];

NSMutableArray * arr1 = [arr copy];

NSMutableArray * arr2 = [arr mutableCopy];

NSLog(@"NSArray地址%p",arr);

NSLog(@"NSArray copy地址%p",arr1);

NSLog(@"NSArray mutableCopy地址%p",arr2);

NSMutableArray * arrM1 = [arrM copy];

NSMutableArray * arrM2 = [arrM mutableCopy];

NSLog(@"NSMutableArray copy地址%p",arrM1);

NSLog(@"NSMutableArray mutableCopy地址%p",arrM1);

}

[objc] view
plain copy

print?

console:

[objc] view
plain copy

print?

2015-11-13 18:29:02.416 0-5 原型模式[2427:192975] NSArray地址0x10030aef0



[objc] view
plain copy

print?

2015-11-13 18:29:02.416 0-5 原型模式[2427:192975] NSArray copy地址0x10030aef0

[objc] view
plain copy

print?

2015-11-13 18:29:02.417 0-5 原型模式[2427:192975] NSArray mutableCopy地址0x10030c0e0

2015-11-13 18:29:02.417 0-5 原型模式[2427:192975] NSMutableArray copy地址0x10020cc80

2015-11-13 18:29:02.417 0-5 原型模式[2427:192975] NSMutableArray mutableCopy地址0x10020d1d0

Program ended with exit code: 0


由以上结果可知iOS中不可变数组的copy为浅拷贝,不可变数组的mutablecopy和可变数组的copy和mutableCopy都是深拷贝。

可变性讨论,给出数组复制后的可变性测试用例

[objc] view
plain copy

print?

-(void)test4

{

NSArray * arr = @[@"2",@"1"];

NSMutableArray * arrM = [NSMutableArray arrayWithArray:arr];

NSMutableArray * arr1 = [arr copy];

NSMutableArray * arr2 = [arr mutableCopy];

NSMutableArray * arrM1 = [arrM copy];

NSMutableArray * arrM2 = [arrM mutableCopy];

[arr1 addObject:@"abc"];//1

[arr2 addObject:@"abc"];//2

[arrM1 addObject:@"abc"];//3

[arrM2 addObject:@"abc"];//4

}

在以上标注的1,3的情况下 console信息如下:

[objc] view
plain copy

print?

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI addObject:]: unrecognized selector sent to instance 0x100205570'

2.结论:

1.NSMutableArray类对象的拷贝都是深拷贝,NSArray 的copy为浅拷贝,mutable copy是深拷贝,得到的新对象的可变性要看是copy还是mutable copy。

2.copy的情况下得到的对象不可变,mutablecopy的情况下得到的对象可变。

继续测试NSDictionary。

测试用例1:

[objc] view
plain copy

print?

-(void)testDictionary

{

NSDictionary * d = [NSDictionary dictionary];

NSDictionary * d2 = [d copy];

NSMutableDictionary * d3 = [d mutableCopy];

NSMutableDictionary * dictM = [NSMutableDictionary dictionary];

NSMutableDictionary * dictM2 = [dictM copy];

NSMutableDictionary * dictM3 = [dictM mutableCopy];

NSLog(@"地址%p",d);

NSLog(@"copy地址%p",d2);

NSLog(@"mutablecopy地址%p",d3);

NSLog(@"地址%p",dictM);

NSLog(@"copy地址%p",dictM2);

NSLog(@"mutablecopy地址%p",dictM3);

}

执行结果:

[objc] view
plain copy

print?

016-01-06 20:18:45.680 1fundation框架[1633:148875] 地址0x1002005b0

2016-01-06 20:18:45.680 1fundation框架[1633:148875] copy地址0x1002005b0

2016-01-06 20:18:45.680 1fundation框架[1633:148875] mutablecopy地址0x100103680

2016-01-06 20:18:45.681 1fundation框架[1633:148875] 地址0x100103a40

2016-01-06 20:18:45.681 1fundation框架[1633:148875] copy地址0x1002005b0

2016-01-06 20:18:45.681 1fundation框架[1633:148875] mutablecopy地址0x100103c60

Program ended with exit code: 0

可变性测试:

在以上代码的基础上添加:

[objc] view
plain copy

print?

[d2 setObject:@"a" forKey:@"aa"];(1)

[d3 setObject:@"a" forKey:@"aa"];

[dictM2 setObject:@"a" forKey:@"aa"];(2)

[dictM3 setObject:@"a" forKey:@"aa"];

1,2处会报错误,也就是说 NSDictionary NSMutableDictionary的copy不可变 mutable copy可变。

结论:

(1) fundation框架中 对象的copy不可变,mutable copy是可变的。

(2)不可变对象的copy是浅拷贝,mutable copy是深拷贝,可变对象的copy和mutable copy是深拷贝。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: