原型

设计模式 / 创建型模式
image

//Prototype
@protocol Shape <NSObject>
@property (nonatomic, copy) NSString *color;

- (id<Shape>)clone;
@end

//ConcretePrototype
@interface Square : NSObject <Shape>
- (instancetype)initWithColor:(NSString *)color;
@end

@implementation Square

//@synthesize is needed: the property comes from the protocol,
//not from @interface
@synthesize color;

- (instancetype)initWithColor:(NSString *)value {
    self = [super init];
    if (self) {
        color = [value copy];
    }
    return self;
}

- (id<Shape>)clone {
    return [[Square alloc] initWithColor:color];
}
@end

//Client
@interface ShapeMaker : NSObject
- (instancetype)initWithShape:(id<Shape>)shape;
- (id<Shape>)makeShape;
@end

@implementation ShapeMaker {
    id<Shape> _shape;
}

- (instancetype)initWithShape:(id<Shape>)shape {
    self = [super init];
    if (self) {
        _shape = shape;
    }
    return self;
}

- (id<Shape>)makeShape {
    return [_shape clone];
}
@end

Square *square = [[Square alloc] initWithColor:@"Red"];
ShapeMaker *maker = [[ShapeMaker alloc] initWithShape:square];

id<Shape> square1 = [maker makeShape];
Square *square2 = (Square *)[maker makeShape];

NSLog(@"%@", square1.color);
NSLog(@"%@", square2.color);


Specify the kinds of objects to create using a prototypical instance, and create new objectsby copying this prototype.
Read more

问题。绘图程序有一个现成图形的调色板,每个图形都有自己的颜色、大小和边框。用户把图形拖到页面上时,程序必须生成一个与之完全相同的新图形。如果代码使用构造函数,就必须知道确切的类,并手动复制每一项设置。于是每增加一种图形,这段代码都要修改。

思路。原型是一个知道如何复制自己的现成对象。它有一个复制方法,通常叫作 clone。客户端保存一个原型,并向它索要副本。客户端不指明具体类,也不知道复制了哪些字段。副本最初拥有与原件相同的数据,此后两个对象彼此独立。

如何阅读示例。原型是一个带有一个值的图形,这个值例如颜色或边数。在大多数语言中,一个客户端对象保存一个原型,只通过向它索要副本来生成新图形。输出显示副本的值与原型相同。有些示例还表明,副本是一个独立的对象,或者修改副本不会改变原型。在值永不改变的语言中,什么也不复制:变体就是改动了一个字段的同一样本。

何时使用。当对象的准备工作代价高昂、又需要许多相似的对象时,使用原型模式。当要创建的类要到程序运行时才能确定时,它也有帮助。字段不多的简单对象不要使用它:构造函数更简单。

常见错误。只在基类中编写复制方法,使它总是创建基类对象。这样,具体原型的副本就丢失了自己的类。每个具体原型都必须创建自己类的对象。