创建型设计模式-原型设计模式
概念
介绍
原型模式是一个创建型的模式。原型二字表明了该模式应该有一个样板实例,用户从这个样板对象中复制一个内部属性一致的对象,这个过程也就是我们称的“克隆”。被复制的实例就是我们所称的“原型”,这个原型是可定制的。原型模式多用于创建复杂的或者构造耗时的实例,因为这种情况下,复制一个已经存在的实例可使程序运行更高效。
定义
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象
使用场景
(1)类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等,通过原型拷贝避免这些消耗。
(2)通过new产生的一个对象需要非常繁琐的数据准备或者权限,这时可以使用原型模式。
(3)一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝。
原型模式UML类图(通用)
UML图原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Prototype类需要具备以下两个条件:
(1)在ios类中就是实现NSCopying协议,
(2)重写NSObject类中- (instancetype)copyWithZone:(NSZone*)zone方法
深拷贝和浅拷贝
深拷贝和浅拷贝左边的图是浅拷贝,右边的图是深拷贝
1浅拷贝可以看出来是拷贝的一个对象的地址,两个对象的地址是一样的
2深拷贝是新生成一个对象,两个对象的地址不一样
1.假如我们用浅拷贝copy了一个对象A,生成一个对象B,要是对这个对象B做了修改,那么这个对象A也会发生变化,同理,修改对象A,对象B也就发生了响应的变化。因此,浅拷贝一般复制的是不可变对象,例如NSString ,NSArray,NSDictionary等
2.而深拷贝是copy的是两个对象,没有任何联系了,所以可以A和B 对象随便修改,都不会影响。
简单demo
浅拷贝
#import@interface Book : NSObject@property (nonatomic,strong) NSString * name;
@property (nonatomic,strong) NSString * auther;
-(void)print;
@end
#import "Book.h"
@implementation Book
-(id)copyWithZone:(NSZone *)zone{
return self;
}
-(void)print{
NSLog(@"start");
NSLog(@"deep 书的名:%@ 书的作者: %@",self.name,self.auther);
NSLog(@"end");
}
@end
浅拷贝调用
-(void)shallowcopy{
Book * book = [Book new];
book.name = @"oc";
book.auther =@"温杰";
[book print];
Book* book2 = [book copy];
[book2 print];
book2.name = @"swift";
[book2 print];
[book print];
}
打印结果
2018-04-02 15:04:53.559524+0800 原型模式-创建型模式[92993:4976971] start
2018-04-02 15:04:53.559710+0800 原型模式-创建型模式[92993:4976971] deep 书的名:oc 书的作者: 刘艳
2018-04-02 15:04:53.560045+0800 原型模式-创建型模式[92993:4976971] end
2018-04-02 15:04:53.560976+0800 原型模式-创建型模式[92993:4976971] start
2018-04-02 15:04:53.561323+0800 原型模式-创建型模式[92993:4976971] deep 书的名:oc 书的作者: 刘艳
2018-04-02 15:04:53.561810+0800 原型模式-创建型模式[92993:4976971] end
2018-04-02 15:04:53.562286+0800 原型模式-创建型模式[92993:4976971] start
2018-04-02 15:04:53.562417+0800 原型模式-创建型模式[92993:4976971] deep 书的名:swift 书的作者: 刘艳
2018-04-02 15:04:53.562833+0800 原型模式-创建型模式[92993:4976971] end
2018-04-02 15:04:53.563567+0800 原型模式-创建型模式[92993:4976971] start
2018-04-02 15:04:53.563797+0800 原型模式-创建型模式[92993:4976971] deep 书的名:swift 书的作者: 刘艳
2018-04-02 15:04:53.564015+0800 原型模式-创建型模式[92993:4976971] end
从浅拷贝这里能看出来,假设我们更改了book2 ,book 的相关属性也发生变化了。
深copy
#import <Foundation/Foundation.h>
@interface BookDeep : NSObject@property (nonatomic,strong) NSString * name;
@property (nonatomic,strong) NSString * auther;
-(void)print;
@end
#import "BookDeep.h"
@implementation BookDeep
-(id)copyWithZone:(NSZone *)zone{
BookDeep * deep=[[BookDeep allocWithZone:zone]init];
deep.name=self.name;
deep.auther = self.auther;
return deep;
}
-(void)print{
NSLog(@"start");
NSLog(@"书的名:%@ 书的作者: %@",self.name,self.auther);
NSLog(@"end");
}
@end
深拷贝调用
-(void)deepCopy{
BookDeep * book = [BookDeep new];
book.name = @"oc";
book.auther =@"刘艳";
[book print];
BookDeep* book2 = [book copy];
[book2 print];
book2.name = @"swift";
[book2 print];
[book print];
}
打印结果
2018-04-02 15:04:53.564353+0800 原型模式-创建型模式[92993:4976971] start
2018-04-02 15:04:53.564496+0800 原型模式-创建型模式[92993:4976971] 书的名:oc 书的作者: 刘艳
2018-04-02 15:04:53.564586+0800 原型模式-创建型模式[92993:4976971] end
2018-04-02 15:04:53.564726+0800 原型模式-创建型模式[92993:4976971] start
2018-04-02 15:04:53.564826+0800 原型模式-创建型模式[92993:4976971] 书的名:oc 书的作者: 刘艳
2018-04-02 15:04:53.564957+0800 原型模式-创建型模式[92993:4976971] end
2018-04-02 15:04:53.565508+0800 原型模式-创建型模式[92993:4976971] start
2018-04-02 15:04:53.566199+0800 原型模式-创建型模式[92993:4976971] 书的名:swift 书的作者: 刘艳
2018-04-02 15:04:53.566480+0800 原型模式-创建型模式[92993:4976971] end
2018-04-02 15:04:53.566786+0800 原型模式-创建型模式[92993:4976971] start
2018-04-02 15:04:53.567067+0800 原型模式-创建型模式[92993:4976971] 书的名:oc 书的作者: 刘艳
2018-04-02 15:04:53.567514+0800 原型模式-创建型模式[92993:4976971] end
更改book2 ,book1 不会产生任何影响
总结
优点
(1)原型模式是在内存中二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量对象时,原型模式可能更好的体现其优点。(ios 其实并没有这一点)
(2)还有一个重要的用途就是保护性拷贝,也就是对某个对象对外可能是只读的,为了防止外部对这个只读对象的修改,通常可以通过返回一个对象拷贝的形式实现只读的限制。(这个用途很重要)
缺点
(1)这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的,在实际开发中应该注意这个潜在问题。优点是减少了约束,缺点也是减少了约束,需要大家在实际应用时考虑。
(2)通过实现NSCopying协议的原型模式在调用copy函数构造实例时并不一定比通过new操作速度快。
使用注意
在ios 中,我们有NSCopying 和NSMutableCopying 协议,最好规范使用
NSCopying 使用在我们那些不可变的对象上。(浅拷贝)
NSMutableCopying 使用在那些我们可以改变的对象上。(深拷贝)
上面的例子写的不是很规范,请参考博客的兄弟注意。
下面贴段规范代码
浅拷贝
#import<Foundation/Foundation.h>
@interface BookShallowCopy : NSObject@property (nonatomic,strong,readonly) NSString * name;
@property (nonatomic,strong,readonly) NSString * auther;
- (instancetype)initWithBookName:(NSString *)name author:(NSString *)author;
-(void)print;
@end
#import "BookShallowCopy.h"
@interface BookShallowCopy()
@property (nonatomic,strong,readwrite) NSString * name;
@property (nonatomic,strong,readwrite) NSString * auther;
@end
@implementation BookShallowCopy
- (instancetype)initWithBookName:(NSString *)name author:(NSString *)author
{
self = [super init];
if (self) {
self.name = name;
self.auther =author;
}
return self;
}
-(id)copyWithZone:(NSZone *)zone{
return self;
}
-(void)print{
NSLog(@"start");
NSLog(@"书的名:%@ 书的作者: %@",self.name,self.auther);
NSLog(@"end");
}
@end
//规范的浅拷贝
-(void)shallowCopyModel{
BookShallowCopy * shallowCopy=[[BookShallowCopy alloc]initWithBookName:@"oc" author:@"刘艳"];
[shallowCopy print];
///用的是copy 而不是mutablecopy
BookShallowCopy * shallowCopy1=[shallowCopy copy];
[shallowCopy1 print];
///不可以修改shallowCopy 的任何属性
// shallowCopy1.name= @"swift";
[shallowCopy print];
}
深拷贝
#import <Foundation/Foundation.h>
@interface BookDeep : NSObject@property (nonatomic,strong) NSString * name;
@property (nonatomic,strong) NSString * auther;
-(void)print;
@end
#import "BookDeep.h"
@implementation BookDeep
-(id)copyWithZone:(NSZone *)zone{
BookDeep * deep=[[BookDeep allocWithZone:zone]init];
deep.name=self.name;
deep.auther = self.auther;
return deep;
}
-(void)print{
NSLog(@"start");
NSLog(@"书的名:%@ 书的作者: %@",self.name,self.auther);
NSLog(@"end");
}
@end
-(void)deepCopyModel{
BookDeepCopy * shallowCopy=[[BookDeepCopy alloc]initWithBookName:@"oc" author:@"刘艳"];
[shallowCopy print];
///用的是mutableCopy 而不是copy 可以改变对象
BookDeepCopy * shallowCopy1=[shallowCopy mutableCopy];
[shallowCopy1 print];
///随便修改,但是不会影响到shallowCopy 对象
shallowCopy1.name= @"swift";
[shallowCopy1 print];
[shallowCopy print];
}
下一篇介绍
参考博客