设计模式之ios实现

创建型设计模式-原型设计模式

2018-04-02  本文已影响19人  充满活力的早晨

概念

介绍

     原型模式是一个创建型的模式。原型二字表明了该模式应该有一个样板实例,用户从这个样板对象中复制一个内部属性一致的对象,这个过程也就是我们称的“克隆”。被复制的实例就是我们所称的“原型”,这个原型是可定制的。原型模式多用于创建复杂的或者构造耗时的实例,因为这种情况下,复制一个已经存在的实例可使程序运行更高效。

定义

用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象

使用场景

(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];

}

源代码地址

下一篇介绍

创建性设计模式-工厂模式

参考博客

设计模式之原型模式

ios原型模式

上一篇下一篇

猜你喜欢

热点阅读