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

来源:互联网 发布:命理探源知乎 编辑:程序博客网 时间:2024/06/05 18:16

1.原型设计模式

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

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

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

1.1 代码设计

以Person类为例

[objc] view plain copy
 print?
  1. #import <Foundation/Foundation.h>  
  2.   
  3. @interface Person : NSObject  
  4. @property (nonatomic,copyNSString * name;  
  5. @property (nonatomic,copyNSString * sex;  
  6. @property (nonatomic,copyNSString * experience;  
  7. //显示  
  8. -(void)display;  
  9.   
  10. -(void)test1;  
  11. -(void)test2;  
  12. @end  
  13. @implementation Person  
  14. -(void)display  
  15. {  
  16.     NSLog(@"姓名:%@",_name);  
  17.     NSLog(@"性别:%@",_sex);  
  18.     NSLog(@"工作经验%@",_experience);  
  19. }  
  20. @end  


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

[objc] view plain copy
 print?
  1. Person * p = [[Person alloc]init];  
  2. p.name = @"name1";  
  3. p.sex = @"男";  
  4. p.experience = @"一年";  
  5. [p display];  
  6. Person * p1 = [[Person alloc]init];  
  7. p1.name = @"name1";  
  8. p1.sex = @"男";  
  9. p1.experience = @"一年";  
  10. [p1 display];  

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

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

1.2 对代码进行重构

[objc] view plain copy
 print?
  1. @interface Person : NSObject  
  2. @property (nonatomic,copyNSString * name;  
  3. @property (nonatomic,copyNSString * sex;  
  4. @property (nonatomic,copyNSString * experience;  
  5.   
  6. //提供原型类的克隆接口  
  7. -(instancetype)clone;  
  8. //显示  
  9. -(void)display;  
  10.   
  11. @end  
  12. @implementation Person  
  13. -(void)display  
  14. {  
  15.     NSLog(@"姓名:%@",_name);  
  16.     NSLog(@"性别:%@",_sex);  
  17.     NSLog(@"工作经验%@",_experience);  
  18. }  
  19. -(instancetype)clone  
  20. {  
  21.     return [self copy];            1)标记
  22. }  
[objc] view plain copy
 print?
  1. -(id)copyWithZone:(NSZone *)zone  
  2. {  
  3.     Prototype * p = [[[self class] alloc]init];  
  4.     p.name = self.name;  
  5.     return p;  
  6. }

@end
[objc] view plain copy
 print?
  1. 为什么要写下面这个方法呢
[objc] view plain copy
 print?
  1. 答案: 以上代码中红色标记位置,是调用该类的copy方法,这个方法是从NSObject继承而来,而这个方法内部会调用copyWithZone方法,这个方法是NSCopying协议里面的,对于任何继承自NSObject的类而言,如果需要使用copy mutablecopy 则需要重载copyWithZone方法或者mutableCopyWithZone方法。
[objc] view plain copy
 print?
  1. 系统类之所以需要不需要重写这两个方法,是因为内部已经重载了。

1.3 什么是原型设计模式

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

其类图如下:

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

1.4 iOS中的原型设计模式

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

看系统内部NSCopying 的声明:

@protocol NSCopying

[objc] view plain copy
 print?
  1. - (id)copyWithZone:(NSZone *)zone;  
  2.   
  3. @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?
  1. {  
  2.     NSString * str = @"abc";  
  3.     NSLog(@"字符串地址%p",str);  
  4.     NSString * str1 = [str copy];  
  5.     NSLog(@"不可变字符串copy后地址%p",str1);  
  6.     NSString * str2 = [str mutableCopy];  
  7.     NSLog(@"不可变字符串mutableCopy后地址%p",str2);  
  8.     NSMutableString * strM = [[NSMutableString alloc]initWithString:@"def"];  
  9.     NSMutableString * strM1 = [strM copy];
[objc] view plain copy
 print?
  1. NSLog(@"可变字符串copy后地址%p",strM1);  
  2.     NSString * strM2 = [strM mutableCopy];  
  3.     NSLog(@"可变字符串的mutablecopy地址%p",strM2);  
  4. }  
[objc] view plain copy
 print?
  1. console的信息:  
[objc] view plain copy
 print?
  1. 2015-11-13 18:13:06.162 0-5 原型模式[2344:187326] 字符串地址0x1000020c0
[objc] view plain copy
 print?
  1. 2015-11-13 18:13:06.164 0-5 原型模式[2344:187326] 不可变字符串copy后地址0x1000020c0         
  2. 2015-11-13 18:13:06.165 0-5 原型模式[2344:187326] 不可变字符串mutableCopy后地址0x1004046e0  
  3. 2015-11-13 18:13:06.165 0-5 原型模式[2344:187326] 可变字符串copy后地址0x66656435  
  4. 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?
  1. -(void)test2  
  2. {  
  3.     //讨论字符串复制后的可变性  
  4.     NSString * str = @"abc";  
  5.     NSMutableString * str1 = [str copy];  
  6.     NSMutableString * str2 = [str mutableCopy];  
  7.       
  8.     NSMutableString * strM = [[NSMutableString alloc]initWithString:@"abc"];  
  9.     NSMutableString * strM1 = [strM copy];  
  10.     NSMutableString * strM2 = [strM mutableCopy];  
  11.     [str1 appendString:@"a"];//1  
  12.     [str2 appendString:@"a"];//2  
  13.     [strM1 appendString:@"a"];//3  
  14.     [strM2 appendString:@"a"];//4  
  15. }  
以上得到NSString NSMu table St ring的copy和mutableCopy字符串之后 分别用NSMutableString接收,然后操作该对象。

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

[objc] view plain copy
 print?
  1. 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?
  1. -(void)test3  
  2. {  
  3.     NSArray * arr = @[@"2",@"1"];  
  4.       
  5.     NSMutableArray * arrM = [NSMutableArray arrayWithArray:arr];  
  6.     NSMutableArray * arr1 = [arr copy];  
  7.     NSMutableArray * arr2 = [arr mutableCopy];  
  8.     NSLog(@"NSArray地址%p",arr);  
  9.     NSLog(@"NSArray copy地址%p",arr1);  
  10.     NSLog(@"NSArray mutableCopy地址%p",arr2);  
  11.       
  12.     NSMutableArray * arrM1 = [arrM copy];  
  13.     NSMutableArray * arrM2 = [arrM mutableCopy];  
  14.       
  15.     NSLog(@"NSMutableArray copy地址%p",arrM1);  
  16.     NSLog(@"NSMutableArray mutableCopy地址%p",arrM1);  
  17. }  
[objc] view plain copy
 print?
  1. console:  
[objc] view plain copy
 print?
  1. 2015-11-13 18:29:02.416 0-5 原型模式[2427:192975] NSArray地址0x10030aef0  
[objc] view plain copy
 print?
  1. 2015-11-13 18:29:02.416 0-5 原型模式[2427:192975] NSArray copy地址0x10030aef0  
[objc] view plain copy
 print?
  1. 2015-11-13 18:29:02.417 0-5 原型模式[2427:192975] NSArray mutableCopy地址0x10030c0e0  
  2. 2015-11-13 18:29:02.417 0-5 原型模式[2427:192975] NSMutableArray copy地址0x10020cc80  
  3. 2015-11-13 18:29:02.417 0-5 原型模式[2427:192975] NSMutableArray mutableCopy地址0x10020d1d0  
  4. Program ended with exit code0  

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

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

[objc] view plain copy
 print?
  1. -(void)test4  
  2. {  
  3.     NSArray * arr = @[@"2",@"1"];  
  4.     NSMutableArray * arrM = [NSMutableArray arrayWithArray:arr];  
  5.     NSMutableArray * arr1 = [arr copy];  
  6.     NSMutableArray * arr2 = [arr mutableCopy];  
  7.     NSMutableArray * arrM1 = [arrM copy];  
  8.     NSMutableArray * arrM2 = [arrM mutableCopy];  
  9.       
  10.     [arr1 addObject:@"abc"];//1  
  11.     [arr2 addObject:@"abc"];//2  
  12.     [arrM1 addObject:@"abc"];//3  
  13.     [arrM2 addObject:@"abc"];//4  
  14. }  
在以上标注的1,3的情况下 console信息如下:

[objc] view plain copy
 print?
  1. 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?
  1. -(void)testDictionary  
  2. {  
  3.     NSDictionary * d = [NSDictionary dictionary];  
  4.     NSDictionary * d2 = [d copy];  
  5.     NSMutableDictionary * d3 = [d mutableCopy];  
  6.     NSMutableDictionary * dictM = [NSMutableDictionary dictionary];  
  7.     NSMutableDictionary * dictM2 = [dictM copy];  
  8.     NSMutableDictionary * dictM3 = [dictM mutableCopy];  
  9.      NSLog(@"地址%p",d);  
  10.     NSLog(@"copy地址%p",d2);  
  11.     NSLog(@"mutablecopy地址%p",d3);  
  12.     NSLog(@"地址%p",dictM);  
  13.     NSLog(@"copy地址%p",dictM2);  
  14.     NSLog(@"mutablecopy地址%p",dictM3);  
  15. }  
执行结果:
[objc] view plain copy
 print?
  1. 016-01-06 20:18:45.680 1fundation框架[1633:148875] 地址0x1002005b0  
  2. 2016-01-06 20:18:45.680 1fundation框架[1633:148875copy地址0x1002005b0  
  3. 2016-01-06 20:18:45.680 1fundation框架[1633:148875] mutablecopy地址0x100103680  
  4. 2016-01-06 20:18:45.681 1fundation框架[1633:148875] 地址0x100103a40  
  5. 2016-01-06 20:18:45.681 1fundation框架[1633:148875copy地址0x1002005b0  
  6. 2016-01-06 20:18:45.681 1fundation框架[1633:148875] mutablecopy地址0x100103c60  
  7. Program ended with exit code0  
可变性测试:

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

[objc] view plain copy
 print?
  1. [d2 setObject:@"a" forKey:@"aa"];(1)  
  2. [d3 setObject:@"a" forKey:@"aa"];  
  3. [dictM2 setObject:@"a" forKey:@"aa"];(2)  
  4. [dictM3 setObject:@"a" forKey:@"aa"];  
1,2处会报错误,也就是说 NSDictionary NSMutableDictionary的copy不可变 mutable copy可变。


结论:

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

(2)不可变对象的copy是浅拷贝,mutable copy是深拷贝,可变对象的copy和mutable copy是深拷贝。

0 0
原创粉丝点击