博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
原型模式与深浅拷贝
阅读量:6712 次
发布时间:2019-06-25

本文共 3753 字,大约阅读时间需要 12 分钟。

原型模式的目的就是通过复制的手段得到一个新的对象。

个人认为这种模式最大的好处是省掉了“工厂”这层概念,因为工厂通常给人的印象是某种初始化动作,而拷贝则是建立在运行时已经生成的对象的基础之上的。

一个更大的好处是可以让拷贝操作作用在聚合根之上,可以一次性拷贝一套复杂的对象集合,对外则屏蔽了赋值过程的细节。

拷贝分为深拷贝和浅拷贝两种,浅拷贝就是建立一个新指针指向同一个对象,即同一个对象多份引用,深拷贝则是完全复制目标对象,生成一个新的对象二进制数据,并用一个新指针指向新的对象。对于浅拷贝,我觉得没什么好说的。

对于深拷贝,java/C#当中都提供了克隆接口(我估计很多人都没直接用过它们),OC则提供了NSCopying协议,OC的很多类(比如词典类)都已经实现了这个协议。

深拷贝要解决的问题分以下几种:普通类的拷贝,子类的拷贝,聚合根的拷贝。

对于一个普通类Book:

1 #import 
2 3 @interface Book : NSObject
4 @property (nonatomic, copy) NSString *name;5 - (id)copyWithZone:(NSZone *)zone;6 @end
1 #import "Book.h" 2  3 @implementation Book 4  5 - (id)copyWithZone:(NSZone *)zone{ 6     Book *copy = [[Book allocWithZone:zone]init]; 7     copy.name = self.name; 8     return copy; 9 }10 11 @end
1 #import 
2 #import "Book.h" 3 4 int main(int argc, const char * argv[]) 5 { 6 @autoreleasepool { 7 Book *book = [[Book alloc]init]; 8 book.name = @"test"; 9 10 Book *book2 = [book copy];11 12 NSLog(@"%@", book2.name); //test13 }14 return 0;15 }

实现拷贝的过程只要实现NSCopying协议当中的方法,并在其中创建一个新的对象就可以了。

当Book类存在子类时,我们希望子类也能够支持拷贝:

1 #import "Book.h"2 3 @interface ProgramingBook : Book 
4 @property (nonatomic, copy) NSString *language;5 - (id)copyWithZone:(NSZone *)zone;6 @end
1 #import "ProgramingBook.h" 2  3 @implementation ProgramingBook 4  5 - (id)copyWithZone:(NSZone *)zone{ 6     ProgramingBook *copy = [super copyWithZone:zone]; 7     copy.language = self.language; 8     return copy; 9 }10 11 @end

这里调用了父类的copyWithZone:方法,因为从对象的内存结构来看,父类的拷贝工作需要由父类自己完成,这点无可厚非。

问题是当调用拷贝方法时:

1 #import 
2 #import "Book.h" 3 #import "ProgramingBook.h" 4 int main(int argc, const char * argv[]) 5 { 6 @autoreleasepool { 7 ProgramingBook *book = [[ProgramingBook alloc]init]; 8 book.name = @"test"; 9 book.language = @"java";10 11 ProgramingBook *book2 = [book copy];12 13 NSLog(@"%@", book2.name);14 NSLog(@"%@", book2.language);15 }16 return 0;17 }

却会报错,出错的代码是子类拷贝方法中的

1 copy.language = self.language;

错误信息是熟悉的unrecognized selector sent to instance 0x100101020 找不到方法。

仔细分析会发现是找不到self对language参数的getter方法,那么就要怀疑这个self到底是什么。

由于子类的拷贝方法调用了父类的拷贝方法,而父类的拷贝方法当中有这样一句话:

1 Book *copy = [[Book allocWithZone:zone]init];

显然,这里分配了一个Book类型的对象,那么self就表示Book类型,它是不存在language的getter方法的。

解决方法是把父类拷贝方法做改造:

1 #import "Book.h" 2  3 @implementation Book 4  5 - (id)copyWithZone:(NSZone *)zone{ 6     Book *copy = [[[self class] allocWithZone:zone]init]; 7     copy.name = self.name; 8     return copy; 9 }10 11 @end

这样就能正确地初始化子类对象的内存空间、以及生成正确的getter方法了。

第三种情况就是对聚合根的拷贝,这里举一个最简单的例子,书当中聚合了一个叫做Pages的集合,其中含有一个页数属性,其他的属性这里略去:

让这个类也实现NSCopying协议,因为在聚合根Book当中,也是要对Pages类进行深拷贝的,而它的深拷贝行为应该是自治的:

1 #import 
2 3 @interface Pages : NSObject
4 @property (nonatomic, assign) NSInteger number;5 - (id)copyWithZone:(NSZone *)zone;6 @end
1 #import "Pages.h" 2  3 @implementation Pages 4  5 - (id)copyWithZone:(NSZone *)zone { 6     Pages *copy = [[[self class] allocWithZone:zone]init]; 7     copy.number = self.number; 8     return copy; 9 }10 11 @end

聚合根类Book定义改为:

1 #import 
2 3 @class Pages;4 5 @interface Book : NSObject
6 @property (nonatomic, copy) NSString *name;7 @property (nonatomic, strong) Pages *pages;8 - (id)copyWithZone:(NSZone *)zone;9 @end
1 #import "Book.h" 2 #import "Pages.h" 3  4 @implementation Book 5  6 - (id)copyWithZone:(NSZone *)zone{ 7     Book *copy = [[[self class] allocWithZone:zone]init]; 8     copy.name = self.name; 9     copy.pages = [self.pages copy];10     return copy;11 }12 13 @end

只要在其中对pages变量进行copy就可以了,这样就能保证聚合根的拷贝操作与被聚合类的拷贝操作不发生耦合。

转载于:https://www.cnblogs.com/Steak/p/3538047.html

你可能感兴趣的文章
温度传感器,ds18b20
查看>>
总结从python2.7和python3.0的语法差异
查看>>
PSP(4.13——4.19)以及周记录
查看>>
ecshop为什么删不掉商品分类
查看>>
spark学习笔记
查看>>
bzoj1941[Sdoi2010]Hide and Seek
查看>>
IT兄弟连 Java Web教程 经典面试题2
查看>>
利用setTimeoutc处理javascript ajax请求超时
查看>>
三、Java基础工具(1)_常用类——字符串
查看>>
文献管理与信息分析》第二讲作业
查看>>
java 遍历arrayList的四种方法
查看>>
根据不同的产品id获得不同的下拉选项 (option传多值)
查看>>
css3新增属性:多列(column)
查看>>
redis 主从配置和集群配置
查看>>
手机3D游戏开发:自定义Joystick的相关设置和脚本源码
查看>>
java 数组偶数排在奇数前面
查看>>
window.frames["detailFrm"].isSubmitting = true;//?起什么作用
查看>>
ASCII表
查看>>
idea之debug
查看>>
什么是真正的流程管理?流程管理的是与不是。
查看>>