zoukankan      html  css  js  c++  java
  • 大话设计模式之原型模式

    原型模式

    何为原型模式

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

    客户端知道抽象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);

    总结

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

  • 相关阅读:
    fedora上部署ASP.NET——(卡带式电脑跑.NET WEB服务器)
    SQL Server 请求失败或服务未及时响应。有关详细信息,请参见事件日志或其它适合的错误日志
    8086CPU的出栈(pop)和入栈(push) 都是以字为单位进行的
    FTP 服务搭建后不能访问问题解决
    指定的 DSN 中,驱动程序和应用程序之间的体系结构不匹配
    Linux 安装MongoDB 并设置防火墙,使用远程客户端访问
    svn Please execute the 'Cleanup' command. 问题解决
    .net 操作MongoDB 基础
    oracle 使用绑定变量极大的提升性能
    尝试加载 Oracle 客户端库时引发 BadImageFormatException。如果在安装 32 位 Oracle 客户端组件的情况下以 64 位模式运行,将出现此问题。
  • 原文地址:https://www.cnblogs.com/qianLL/p/5248461.html
Copyright © 2011-2022 走看看