大话设计模式之原型模式

原型模式

何为原型模式

使用原型模式实例创建对象的种类,并通过复制这个原型创建新的对象

客户端知道抽象Prototype类,在运行时,抽象Prototype子类的任何对象都可以案客户端的意愿被复制,因此,无需手工创建就可以制造同一类的多个实例。

何时使用原型模式

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

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

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

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

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

如:有多相关的类,其行为略有不同,而且主要差异在于内部属性,如名称,图像等

  需要使用组合(树形)对象作为其他东西的基础,例如,在使用组合对象作为组件来构建另一个组合的对象

注意

有个使用原型对象的常见误解,原型对象是典型对象,从不实际使用,这一误解专注于实现次模式的一种特定方式,从功能的角度来看,不管什么对象,只要复制自身比手工要好,都可以是原型对象

深复制和浅复制

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        //只要是拷贝出来的额对象,拷贝出来的对象中的内容和以前对象中的内容一致
        //“一般”情况下拷贝会生成一个新的对象
        //为什么会产生一个新的对象 1.因为拷贝要求修改原来的对象不能影响到拷贝出来的对象
        //修改拷贝出来的对象也不能影响到原来的对象,所以需要生成一个新的对象
        //2.由于以前的对象是一个不可变的对象,而是通过mutableCopy拷贝出来的对象必须是一个可变的对象,所以必须生成一个新的对象
        //会生成新的一个新的对象
    /*    //为什么会产生新的对象,1.因为拷贝
        NSString *scrStr=@"qll";
        NSMutableArray *copystr=[scrStr mutableCopy];
        NSLog(@"scrStr=%@,copyStr=%@",scrStr,copystr);*/
        
         //会生成新的一个新的对象
     /*   NSMutableString *srcStr=[NSMutableString stringWithFormat:@"qll"];
        NSMutableString *copyStr=[srcStr mutableCopy];
        [srcStr appendString:@" COOL"];
        NSLog(@"srcStr=%@",srcStr);
        NSLog(@"copyStr=%@",copyStr);*/
        
         //会生成新的一个新的对象
     /*   NSMutableString *srcStr=[NSMutableString stringWithFormat:@"all"];
        NSString *copyStr=[srcStr copy];
        [srcStr appendString:@" cool"];
        
        NSLog(@"scrStr=%@,copyStr=%@",srcStr,copyStr);*/
        
        //没有生成新的对象
        //原因:因为原来的对象是不能修改的,拷贝出来的对象一晚上不能修改的
        //既然两个都不能修改,所以永远不能影响到另外一个对象,那么已经符合要求
        //所以:OC为了对内存进行优化,就不会生成一个新的对象
        NSString *str=@"lnj";
        NSString *copyStr=[str copy];
        NSLog(@"%p, %p",str,copyStr);
        /*
            如果,没有生成新的对象,我们称之为浅拷贝,本质就是指针拷贝
            如果,生成了新的对象,我们称之为深拷贝,本质就是创建了一个新的对象,内容拷贝
         */
        
    }
    return 0;
}

原型模式的实现

Cocoa Touch框架为NSObject的派生类提供了实现深复制的协议。NSObject的子类需要实现NSCopying协议机器方法----(id)copyWithZone:(NSZone *)zone。NSObject有一个实力方法叫做(id)copy。默认的copy方法调用[self copyWithZone:nil],对于采纳了NSCopying协议的子类,需要实现这个方法,否则引发异常。iOS中,这个保持新的副本对象,然后将其返回,此方法的调用要负责释放返回的对象

代码实现

Resume.h文件

#import <Foundation/Foundation.h>

@interface Resume : NSObject<NSCopying,NSMutableCopying>
@property(copy,nonatomic)NSString *name;
@property(nonatomic,copy)NSString *sex;
@property(nonatomic,assign)int age;
@property(copy,nonatomic)NSString *timeArea;
@property(copy,nonatomic)NSString *company;
@end

Resume.m文件

#import "Resume.h"

@implementation Resume
- (NSString *)description
{
    return [NSString stringWithFormat:@"name=%@,age=%d,sex=%@,timeArea=%@,company=%@", _name,_age,_sex,_timeArea,_company];
}
-(id)copyWithZone:(NSZone *)zone{
    Resume *resume=[[[Resume class] allocWithZone:zone]init];
    resume.age=_age;
    resume.name=_name;
    resume.sex=_sex;
    resume.timeArea=_timeArea;
    resume.company=_company;
    return resume;
}

-(id)mutableCopyWithZone:(NSZone *)zone{
    return [self copyWithZone:zone];
}
@end

客户端

#import <Foundation/Foundation.h>
#import "Resume.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Resume *a=[Resume new];
        a.name=@"大鸟";     
        a.age=20;
        a.sex=@"";
        a.company=@"百度";
        a.timeArea=@"2016-2017";
        
        Resume *b=[a copy];
        b.company=@"腾讯";
        b.timeArea=@"2014-2015";
        NSLog(@"%@",a);
        NSLog(@"%@",b);
        
        
    }
    return 0;
}

效果

假如有个子类继承Resume类的话,并且子类有自己特有的属性,如果其想要使用期特有的属性,需要重写

(id)copyWithZone:(NSZone *)zone方法
例如:子类
workExperience.h文件
#import "Resume.h"

@interface workExperience : Resume
@property(copy,nonatomic)NSString *workdate;

@end
workExperience.m文件
@implementation workExperience
- (NSString *)description
{
    return [NSString stringWithFormat:@"name=%@,age=%d,sex=%@,timeArea=%@,company=%@,workDate=%@",[self name],[self age],[self sex],[self timeArea],[self company],_workdate];
}
-(id)copyWithZone:(NSZone *)zone{
    id obj=[[self class] allocWithZone:zone];
    [obj setAge:[self age]];
    [obj setName:[self name]];
    [obj setAge:[self age]];
    [obj setCompany:[self company]];
    [obj setTimeArea:[self timeArea]];
    [obj setWorkdate:_workdate];
    return obj;
}
@end

客户端

 workExperience *work=[[workExperience alloc]init];
        work.name=@"大鸟";
        work.age=20;
        work.sex=@"";
        work.company=@"百度";
        work.timeArea=@"2016-2017";
        work.workdate=@"8小时";
        workExperience *work1=[work copy];
        work1.workdate=@"12小时";
        
        NSLog(@"%@",work);
        NSLog(@"%@",work1);

总结

当需要生成真正的副本的时候,必须要实现深复制,这样才可以对对象进行后续的操作

原文地址:https://www.cnblogs.com/qianLL/p/5248461.html