Modo de prototipo de patrones de diseño de uso común en iOS

Definición de patrón de prototipo

El modo de prototipo (Prototipo) es el modo aplicado a la operación de "copia". Este modo se definió originalmente en el "Modo de diseño" (Addison-Wesley, 1994), que se define como "Utilice la instancia del prototipo para especificar el tipo de objeto a crear y copiar Este prototipo crea nuevos objetos ". Entenderlo simplemente es crear un nuevo objeto basado en este prototipo, esta creación se refiere a una copia profunda para obtener un nuevo recurso de memoria, en lugar de una nueva referencia de puntero. Utilice la instancia del prototipo para especificar el tipo de objeto que se creará y cree un nuevo objeto copiando este prototipo.


Cuando la composición de una clase es más compleja, como contener múltiples componentes o múltiples atributos de clase personalizados, es mucho más simple copiar directamente el objeto actual que crear el objeto desde cero, y el modo de prototipo es el más apropiado. O la diferencia entre objetos no es grande, pero cuando varias propiedades son diferentes, también se puede usar el modo prototipo, siempre que se herede la misma clase padre.


Entorno aplicable 


El objeto a crear debe ser independiente de su tipo y método de creación. 

La clase de la que se va a crear una instancia se determina en tiempo de ejecución. 

No quiero que el nivel de fábrica corresponda al nivel de producto. 

La diferencia entre instancias de diferentes clases es solo una combinación de estados. (Número de copia del prototipo correspondiente que el trabajo manual más fácil de instanciar) 

Las clases no son fáciles de crear. (Será más fácil copiar objetos combinados existentes y modificar la copia) 



Conocimiento principal involucrado: copiar y copiar


Con respecto a la copia profunda y la copia superficial (copia profunda y copia superficial), puede consultar un artículo de mi blog. El registro de aprendizaje de la copia profunda y la copia superficial en iOS  no se presentará aquí.



Tomemos un ejemplo. Primero, creemos algunos datos falsos, para que estos datos falsos se vean, mucho, parece ser más difícil crear un elemento de este tipo, a través de estos datos falsos, cárguelos en la vista de control que queremos operar.


Crear clase de persona de datos falsos


Archivo de punto 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



Cargar datos falsos

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

A continuación, arrastramos un GMGridView al proyecto y algunos datos de imagen para facilitar nuestra visualización.




Ingrese a la página de visualización, es así



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



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



Supongo que te gusta

Origin blog.csdn.net/u010670117/article/details/48109025
Recomendado
Clasificación