iOSで一般的に使用されるデザインパターン-プロトタイプモード

プロトタイプパターンの定義

プロトタイプモード(プロトタイプ)は、「コピー」操作に適用されるモードです。このモードは、元々「デザインモード」(Addison-Wesley、1994)で定義され、「プロトタイプインスタンスを使用してのタイプを指定する」と定義されています。作成するオブジェクトとコピーこのプロトタイプは新しいオブジェクトを作成します。」これを理解するには、このプロトタイプに基づいて新しいオブジェクトを作成するだけです。この作成は、新しいポインタ参照ではなく、新しいメモリリソースを取得するためのディープコピーを指します。プロトタイプインスタンスを使用して、作成するオブジェクトのタイプを指定し、このプロトタイプをコピーして新しいオブジェクトを作成します。


複数のコンポーネントや複数のカスタムクラス属性を含むなど、クラスの構成がより複雑な場合は、オブジェクトを最初から作成するよりも現在のオブジェクトを直接コピーする方がはるかに簡単であり、プロトタイプモードが最適です。または、オブジェクト間の違いは大きくありませんが、複数のプロパティが異なる場合は、同じ親クラスが継承されていれば、プロトタイプモードを使用することもできます。


該当する環境 


作成するオブジェクトは、そのタイプや作成方法に依存しない必要があります。 

インスタンス化されるクラスは実行時に決定されます。 

製品レベルに対応する工場レベルは必要ありません。 

異なるクラスのインスタンス間の違いは、状態の組み合わせのみです。(手作業よりも対応するプロトタイプのコピー番号がインスタンス化されやすい) 

クラスの作成は簡単ではありません。(既存の結合されたオブジェクトをコピーして、コピーを変更する方が簡単です) 



関係する主な知識:コピー&コピー


ディープコピーとシャローコピー(ディープコピーとシャローコピー)について、私のブログの記事参照してください。iOSでのディープコピーとシャローコピーの学習記録は ここでは紹介しません。



例を見てみましょう。最初に、いくつかの偽のデータを作成して、これらの偽のデータが非常に多く見えるようにします。これらの偽のデータを使用して、操作する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个不同的内存地址,所以修改互不干扰



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



おすすめ

転載: blog.csdn.net/u010670117/article/details/48109025