解說21種設計模式之第一篇_原型模式(對象建立型)

原型模式概念:git

  • 把某些對象變成」塑膠印章",讓其擁有「複製」自身並獲得其複製品的能力。
  • 「複製」指:用同一個模具,生產一系列的產品。這些產品只是某些顏色,特徵不一樣而已,只需進行簡單修改。
  • 原型模式「複製」的對象都是真實的副本實例;

原型模式定義:github

  • 應用「複製」操做的模式,稱爲原型模式。

原型模式UML圖以下:數組

客戶端引用着抽象父類Prototype類,父類Prototype類定義了clone的方法,Prototype類的子類實現clone方法; app

什麼時候考慮使用原型模式呢? 框架

  • 不想要產品工廠
  • 不一樣實例間的差別僅僅是屬性狀態的不一樣,所以複製比手工建立更加便捷。
  • 手工建立不容易。像複雜的組合對象,建立起來沒有複製來的快。

Cocoa Touch框架中的應用 函數

NSCopying協議
Cocoa Touch爲NSObject的派生類提供了實現深複製的協議NSCopying;
NSObject的子類須要實現協議NSCopying的方法copyingWithZone:

 

NSObject根類性能

NSObject提供的實例方法copy底層調用也是copyingWithZone:
因此遵照了NSCopying協議的對象,須要實現方法copyingWithZone,否則會引發異常。

 

實際例子以下: atom

如今須要作個畫板功能,功能點兩個:1.實現畫線;2.實現畫點;
線的特性:顏色,寬度;
點的特徵:顏色,Size大小;

下面設計了三個類和一個協議來表示它們的邏輯關係。
 
第一個版本設計: 不具有「複製」能力的簡單自定義對象
基本關係類型的UML圖
代碼實現以下:
Mark協議:
@protocol Mark <NSObject>
@property (nonatomic, assign) CGSize size;
@property (nonatomic, strong) UIColor *color;
@property (nonatomic, assign) CGPoint location;

- (void)addMark:(id<Mark>)mark;
- (void)removeMark:(id<Mark>)mark;
@end

Vertex類:最簡單,它只須要表示一個位置spa

@implementation Vertex
@synthesize location = _location;
@dynamic color,size;

@end

Dot類:繼承自Vertex, 因爲其表示一個獨立的點,因此有size,color屬性值設計

@implementation Dot
@synthesize color = _color, size = _size;

@end

Stroke類:是有若干個Vertex鏈接而成的線段。

@implementation Stroke
@dynamic location;
@synthesize color = _color, size = _size;
#pragma mark - Life Cycle

#pragma mark - Getter, Setter
- (CGPoint)location {
    return [self.marksArray.firstObject location];
}

 

第二版本:具有「複製」能力的加強型自定義對象(原型模式)

代碼實現以下:
Mark協議:
@protocol Mark <NSObject>
@property (nonatomic, assign) CGSize size;
@property (nonatomic, strong) UIColor *color;
@property (nonatomic, assign) CGPoint location;

- (void)addMark:(id<Mark>)mark;
- (void)removeMark:(id<Mark>)mark;
- (id<Mark>)copy;
@end

Vertex類:新增了一個經過自身location建立的構造函數,爲子類建立作準備

@implementation Vertex
@synthesize location = _location;
@dynamic color,size;

- (instancetype)initWithLocation:(CGPoint)location {
    self = [super init];
    if (self) {
        _location = location;
    }
    return self;
}

- (id)copyWithZone:(NSZone *)zone {
    Vertex *ver = [[[self class] alloc] initWithLocation:self.location];
    return ver;
}
@end

Dot類:先經過父類的構造函數建立新對象,再對新對象設置屬性

@implementation Dot
@synthesize color = _color, size = _size;

- (id)copyWithZone:(NSZone *)zone {
    Dot *dot = [[[self class] alloc] initWithLocation:self.location];
    dot.size = self.size;
    dot.color = [UIColor colorWithCGColor:[self.color CGColor]];
    return dot;
}
@end
Stroke類:先建立一個新對象,同時遍歷舊對象的marksArray數組,對裏面的全部對象(id<Mark>)
逐個進行copy
@implementation Stroke
@dynamic location;
@synthesize color = _color, size = _size;
#pragma mark - Life Cycle


#pragma mark - Getter, Setter
- (CGPoint)location {
    return [self.marksArray.firstObject location];
}

#pragma mark - Private Method
- (id)copyWithZone:(NSZone *)zone {
    Stroke *stroke = [[[self class] alloc] init];
    stroke.color = [UIColor colorWithCGColor:[self.color CGColor]];
    stroke.size = self.size;

    NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:[self.marksArray count]];
    for (id<Mark> mark in self.marksArray) {
        [arrayM addObject:[mark copy]];
    }
    stroke.marksArray = arrayM;

    return stroke;
}
@end

 

對例子的實際使用
在觸摸回調方法中記錄觸摸點信息
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event

在全局變量中記錄觸摸點信息並設置屬性監控,當有觸摸點改變就觸發監控函數,在監控函數中進行圖像繪製

[self.scribble addObserver:self forKeyPath:@"mark" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context

 

項目效果圖以下:

原型模式在平時開發的複雜模型中使用頻率較大,合理使用對於提升app性能有很好的做用。

具體在(Objective-C_Design_Patterns)WorkSpace下的(Design_Patterns_Demoes)Project項目下。
相關文章
相關標籤/搜索