iOS commonly used design patterns-prototype mode

Definition of prototype pattern

The prototype mode (Prototype) is the mode applied to the "copy" operation. This mode was originally defined in the "Design Mode" (Addison-Wesley, 1994), which is defined as "Use the prototype instance to specify the type of object to be created, and copy This prototype creates new objects". To understand it simply is to create a new object based on this prototype. This creation refers to a deep copy to obtain a new memory resource, rather than a new pointer reference. Use the prototype instance to specify the type of object to be created, and create a new object by copying this prototype.


When the composition of a class is more complex, such as containing multiple components or multiple custom class attributes, it is much simpler to directly copy the current object than to create the object from scratch, and the prototype mode is most appropriate. Or the difference between objects is not big, but when several properties are different, prototype mode can also be used, provided that the same parent class is inherited.


Applicable environment 


The object to be created should be independent of its type and creation method. 

The class to be instantiated is determined at runtime. 

Do not want the factory level corresponding to the product level. 

The difference between instances of different classes is only a combination of states. (Copy number of the corresponding prototype than hand work easier instantiated) 

Classes are not easy to create. (It will be easier to copy existing combined objects and modify the copy) 



Main knowledge involved: copy & copy


Regarding deep copy and shallow copy (deep copy & shallow copy), you can refer to an article in my blog. The learning record of deep copy and shallow copy in iOS  will not be introduced here.



Let's take an example. First, let's create some fake data, so that these fake data look, a lot, it seems to be more difficult to create such an item, through these fake data, load it to the ViewControllview we want to operate


Create fake data Person class


Point h file

//  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



Load fake data

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

Next, we drag a GMGridView into the project and some image data to facilitate our display




Enter the display page, it's like this



我们现在假设,如果我们想创建一个新的数据,但是这个数据又和之前的类似,但又有一些要修改的地方,例如我们修改头像,那么我们应该要怎么做呢? 我们可以像一开始那样重新创建一个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个不同的内存地址,所以修改互不干扰



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



Guess you like

Origin blog.csdn.net/u010670117/article/details/48109025