iOS设计模式的学习记录 (2) --- 原型模式

来源:互联网 发布:windows xpphotoshop 编辑:程序博客网 时间:2024/05/01 05:02

原型模式的定义

原型模式(Prototype)即应用于“复制”操作的模式,此模式最初定义在《设计模式》(Addison-Wesley,1994),里面是这样定义的“使用原型实例指定创建对象的种类,并通过复制这个原型创建新的对象”。简单来理解就是根据这个原型创建新的对象,这种创建是指深复制,得到一份新的内存资源,而不是一个新的指针引用。使用原型实例指定创建对象的种类,并通过复制这个原型创建新的对象.


当一个类的组成比较复杂,例如包含多个组件或多个自定义类属性的时候,直接复制当前对象比从头开始创建对象要简单得多,则使用原型模式最为合适。又或者对象间的区别不大,只是几个属性不同的时候,也可以使用原型模式,前提是要继承同一个父类。


适用环境 


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

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

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

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

类不容易创建。(复制已有的组合对象并对副本进行修改会更容易) 



主要涉及的知识:复制&copy


关于深复制与浅复制(深拷贝&浅拷贝),可以参考我博客里的一篇文章iOS中的深拷贝和浅拷贝的学习记录 这里就不过多介绍了.



我们来举一个例子,首先我们先创建一些假数据,让这些假数据看起来,很多,显得创建一个这样的item会比较难,通过这些假数据,加载到我们要操作的ViewControllview上面


创建假数据Person类


点h文件

//  PersonItem.h//  原型模式CSDN////  Created by 王颜龙 on 13-12-30.//  Copyright (c) 2013年 longyan. All rights reserved.//#import <Foundation/Foundation.h>@interface PersonItem : NSObject<NSCopying>@property (nonatomic, strong)UIImage        *headerImg;//头像@property (nonatomic, assign)int            age;//年纪@property (nonatomic, assign)CGFloat        height;//身高@property (nonatomic, assign)CGFloat        weight;//体重@property (nonatomic, assign)int            numID;//学号@property (nonatomic, assign)int            classNum;//学年@property (nonatomic, assign)int            score1;//分数1@property (nonatomic, assign)int            score2;//分数2@property (nonatomic, assign)int            score3;//分数3@property (nonatomic, assign)int            score4;//分数4@property (nonatomic, assign)int            score0;//分数0@property (nonatomic, assign)BOOL           isChoose;//判断是否被选中@end



加载假数据

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];    // Override point for customization after application launch.        NSMutableArray *arr = [[NSMutableArray alloc]initWithCapacity:0];        //制作假数据    for (int i = 0; i < 10; i++) {        PersonItem *item = [[PersonItem alloc]init];        item.headerImg = [UIImage imageNamed:[NSString stringWithFormat:@"%d",i+1]];        item.age = 15+i;        item.height = 165+i;        item.weight = 120+i;        item.numID = 100+i;        item.classNum = 10+i;        item.score0 = 100+i;        item.score1 = 90+i;        item.score2 = 80+i;        item.score3 = 70+i;        item.score4 = 60+i;        item.isChoose = NO;        [arr addObject:item];    }        EditViewController *vc = [[EditViewController alloc]initWithItem:arr];        UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:vc];        self.window.rootViewController = nav;        self.window.backgroundColor = [UIColor whiteColor];    [self.window makeKeyAndVisible];    return YES;}

接下来,我们往项目里拖拽一个GMGridView,和一些图片数据,方便我们的展示




进入展示页面,是这样的



我们现在假设,如果我们想创建一个新的数据,但是这个数据又和之前的类似,但又有一些要修改的地方,例如我们修改头像,那么我们应该要怎么做呢? 我们可以像一开始那样重新创建一个preson类的item


PersonItem *item = [[PersonItem alloc]init];        item.headerImg = [UIImage imageNamed:[NSString stringWithFormat:@"%d",i+1]];        item.age = 15+i;        item.height = 165+i;        item.weight = 120+i;        item.numID = 100+i;        item.classNum = 10+i;        item.score0 = 100+i;        item.score1 = 90+i;        item.score2 = 80+i;        item.score3 = 70+i;        item.score4 = 60+i;        item.isChoose = NO;

但是如果要是创建100个,1000个的话,实际上这样做是不太合理的,这个时候就要用到我们的原型模式了.

再次说一下原型模式的定义:当一个类的组成比较复杂,例如包含多个组件或多个自定义类属性的时候,直接复制当前对象比从头开始创建对象要简单得多,则使用原型模式最为合适。


在这里GMGridView的初始化以及一些修改 我就不写了,很简单,重点写一下3个按钮得方法


#pragma bottomView method//错误复制的方法- (void)errorItem{    if (self.chooseArr.count == 0) {        return;    }        PersonItem *item = [self.chooseArr objectAtIndex:0];        item.headerImg = [UIImage imageNamed:@"15"];        [self.selectedItems addObject:item];        [self.gridView reloadData];}//正确复制的方法- (void)copyItem{    if (self.chooseArr.count == 0) {                return;    }    PersonItem *itemNew = [[self.chooseArr objectAtIndex:0] copy];    itemNew.headerImg = [UIImage imageNamed:@"15"];    [self.selectedItems addObject:itemNew];        [self.gridView reloadData];}//删除按钮- (void)delItem{    if (self.chooseArr.count == 0) {                return;    }        if (self.selectedItems.count <=1) {                return;    }        [self.selectedItems removeObject:[self.chooseArr objectAtIndex:0]];    [self.chooseArr removeAllObjects];    [self.gridView reloadData];}

如果你点击了错误复制的方法,你会发现




你会发现什么,你复制了新的item,但是旧的item的头像也跟着改变了,这是为什么呢?我们看一下打印台




他们两个的内存地址是一样的,也就是说指针指向的是同一块内存地址,所以你修改了A,B自然也会变,也就是所谓浅拷贝.


这时如果你删除你会发现,他们都消失了



想避免这种方法的话,我们就要对person类实现深拷贝,那么就要遵循NSCopying协议,代码如下

#import "PersonItem.h"@implementation PersonItem//遵守NSCopying协议,深复制出一个新的item- (id)copyWithZone:(NSZone *)zone{        PersonItem *item = [[[self class]allocWithZone:zone]init];        item.headerImg = [_headerImg copy];    item.age = _age;    item.height = _height;    item.weight = _weight;    item.numID = _numID;    item.classNum = _classNum;    item.score0 = _score0;    item.score1 = _score1;    item.score2 = _score2;    item.score3 = _score3;    item.score4 = _score4;        return item;}@end

这样如果你选择正确的复制的话,结果就会是这样的



原因自然是他们分别是2个不同的内存地址,所以修改互不干扰



这就是我理解的原型模式,如有错误,希望大家指正.


源码:iOS设计模式之原型模式


参考文章:iphone(ios开发)之23种设计模式简介 原型模式

0 0
原创粉丝点击