Objective-C之原型模式

原型模式

原型模式是非常简单的一种模式,在我们的实际开发中经常用到这种模式,例如你创建的可变字典、可变字符串调用copy来生成新的对象,那么你在这个过程中已经使用了原型模式。还有比如你在写论文的时候,给老师交的初稿,退回来之后再修改你肯定不是在初稿上修改的,也不是再从新敲一遍,而是复制一份初稿再修改,这个拷贝初稿生成终稿的过程就叫原型模式。

举个例子:你创建了一个Student类,属性有性别sex、名字name、年级className、班主任teacher、年龄years。然后开始创建学生对象:小江、小帅、小虎等多个对象,在创建的过程中发现这些人是同班学生、除了性别和名字有差别之外其他的信息基本一样,如果初始化这些学生对象然后给每个属性赋值,显然这些代码都是重复性的代码。so通过让Student类遵守NSCopying的协议,就能通过copy快速的初始化对象,然后根据差异简单的改变sex和那么即可。(ps:例子只是为了说明这种模式,相信大家还有很多更好的办法,我现在在学习GoF的《Objective-C的编程之道,iOS设计模式解析》所以现在以简书的形式来做个笔记供大家相互学习和指正,之后会不断的将在这本书理解到的东西转到简书上)

原型模式的定义:使用原型实例指定创建对象的种类,并通过复制这个原型创建新的对象。《设计模式》(Addison-Weslet,1994)


 何时使用原型模式:

        1、需要创建的对象应独立于其类型与创建方式。

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

        3、不想要与产品层次相对应的工厂层次。

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

        5、类不容易创建,比如每个组件可把其他组件作为子节点的组合对象。复制已有的组合对象并对副本进行修改会更加容易。

在GoF的书中有句话很好:从功能的角度来看,不管什么对象,只要复制本身比手工实例化要好,那么都可以是原型对象。使用设计模式更像艺术行为而非科学行为。


深拷贝&浅拷贝

浅拷贝:只是复制指针,且复制的指针的指向还是原来的内存资源,并没有在内存中开辟新的资源,和原来的指针指向一块内存资源。

深拷贝:不但拷贝了指针,而且也将原指针指向的资源进行了拷贝,相当于开辟了新的内存,把原来的资源也拷贝了一份并且各自的指针指向各自的资源。

Coco Touch 框架中根类(NSOblect)的衍生类提供了实现深复制的协议(NSCopying)。NSObject有一个实例方法(id)copy,这个方法默认调用了[self copyWithZone:nil],对于引用了NSCopying协议的子类,必须实现(id)copyWithZone:(NSZone *)zone方法,否则将引发异常。(输出如下)


assign&copy&retain

直接看例子

@interface IDStudent : NSObject

@property (assign, nonatomic, getter=isMale)BOOL male;

@property (copy, nonatomic)NSString *name;

@property (copy, nonatomic)NSString *className;

@property (copy, nonatomic)NSString *teacher;

@property (assign, nonatomic)NSUInteger years;

@property (assign, nonatomic)NSMutableString *name1;

@property (retain, nonatomic)NSMutableString *name2;

@property (copy, nonatomic)NSMutableString *name3;

+ (instancetype)studentWithName:(NSString *)name male:(BOOL)male className:(NSString *)className teacher:(NSString *)teacher yeas:(NSUInteger)years;

@end

 NSMutableString *str =[NSMutableString stringWithFormat:@"小帅"];   

IDStudent *student =[IDStudent new];    

student.name1 =str;    

student.name2 =str;    

student.name3 =str;         

NSLog(@"\n str的地址:%p\n name1的地址:%p(assign) \n name2的地址:%p(retain)\n name3的地址:%p(copy)\n",str,student.name1,student.name2,student.name3);


输出结果

str的地址:0x60c000240e10

name1的地址:0x60c000240e10(assign)

name2的地址:0x60c000240e10(retain)

name3的地址:0x60c000036760(copy)

结论:

解析一下代码:NSMutableString *str =[NSMutableString stringWithFormat:@"小帅"];

1、在栈区开辟内存来存str,比如地址为:0xFFFF,内容为0x60c000240e10

2、在堆区开辟内存来存str的内容@"小帅",地址为0x60c000240e10,内容为@"小帅"

assing:如果在MRC的情况下打印retainCount,它的值不会加1,(自己可以试试),且在堆区的地址还是和str的地址一样,说明assign只是一个str的影子

retain:这个接触到MRC的情况下,它的值会加1,虽然它的地址还是和str的一样,但是它会在栈区开辟新的空间比如0xWWWW,但是内容还是0x60c000240e10相当于经过retain的name2在栈区开辟了新的空间,都是强指向在堆区地址为0x60c000240e10的内容,共同管理。

copy:使用copy后堆区的地址改变,说明这个过程在栈区开辟了新的空间地址为0xBBBB,储存的内容为0x60c000036760同样也在堆区开辟了新的空间,地址为:0x60c000036760内容为@“小帅”。跟原来的str没有了关系,说明进行了深拷贝。


下边对NSString在进行一下实验,看是否和NSMutableString一样的储存方式

NSString *name =[NSString stringWithFormat:@"name"];    

NSString *nameCopy =[name copy];    

NSMutableString *mName =[name mutableCopy];    

NSLog(@"\nname:%p\nnameCopy:%p\nmName:%p\n",name,nameCopy,mName);         

NSMutableString *str =[[NSMutableString alloc]initWithString:@"test"];    

NSMutableString *copyStr =[str copy];    

NSLog(@"\n------------------------------------\nstr:%p\ncopyStr:%p",str,copyStr);

输出结果:

2017-12-22 16:34:02.566672+0800 desgin_原型模式[25958:11425087]

name:0xa000000656d616e4

nameCopy:0xa000000656d616e4

mName:0x60c00024c360

2017-12-22 16:34:02.566808+0800 desgin_原型模式[25958:11425087]

------------------------------------------------------------------------

str:0x60c00024ca50

copyStr:0xa000000747365744

结论:根据输出结果NSString的不可变字符串在copy的情况地址一致,由于copy返回的是不可变副本,系统只生成一份内存资源,此时的copy只是浅拷贝,和retain作用一样。

通过mutableCopy地址不一致,生成的是可变副本,开辟了新的内存空间,是深拷贝。而NSMutableString的copy会开辟新的空间。

本文代码

ps:第一次写文章,想要改变一下自己,之前习惯做笔记,现在也要分享各位同学,这篇文章参考了好多的这位哥们的这篇博客,我写的有什么不对的地方希望大家多多指正!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,825评论 4 377
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,887评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,425评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,801评论 0 224
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,252评论 3 299
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,089评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,216评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 31,005评论 0 215
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,747评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,883评论 2 255
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,354评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,694评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,406评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,222评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,242评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,017评论 2 281

推荐阅读更多精彩内容