文档章节

解说21种设计模式之第一篇_原型模式(对象创建型)

o
 osc_gu9d45li
发布于 2019/04/05 19:30
字数 1046
阅读 13
收藏 0

精选30+云产品,助力企业轻松上云!>>>

原型模式概念:

  • 把某些对象变成”塑胶印章",让其拥有“复制”自身并得到其复制品的能力。
  • “复制”指:用同一个模具,生产一系列的产品。这些产品只是某些颜色,特征不同而已,只需进行简单修改。
  • 原型模式“复制”的对象都是真实的副本实例;

原型模式定义:

  • 应用“复制”操作的模式,称为原型模式。

原型模式UML图如下:

客户端引用着抽象父类Prototype类,父类Prototype类定义了clone的方法,Prototype类的子类实现clone方法; 

何时考虑使用原型模式呢? 

  • 不想要产品工厂
  • 不同实例间的差异仅仅是属性状态的不同,因此复制比手工创建更加便捷。
  • 手工创建不容易。像复杂的组合对象,创建起来没有复制来的快。

Cocoa Touch框架中的应用 

NSCopying协议
Cocoa Touch为NSObject的派生类提供了实现深复制的协议NSCopying;
NSObject的子类需要实现协议NSCopying的方法copyingWithZone:

 

NSObject根类

NSObject提供的实例方法copy底层调用也是copyingWithZone:
所以遵守了NSCopying协议的对象,需要实现方法copyingWithZone,不然会引起异常。

 

实际例子如下: 

现在需要做个画板功能,功能点两个: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类:最简单,它只需要表示一个位置

@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项目下。

 

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。

暂无文章

unity的UGUI之中锚点(Anchors)和中心点(Pivot)、Shift和Alt键功能

在UGUI的控件属性之中,最上方的Rect Transform一栏可以看到锚点和中心点: 锚点Anchors 控件用于定位自身的基准点 可以点击左上角的方框,在其中选择锚点的不同方式: 注意图中,黄色的小点...

路过暴风
56分钟前
7
0
如何将div放置在其容器的底部? - How can I position my div at the bottom of its container?

问题: Given the following HTML: 鉴于以下HTML: <div id="container"> <!-- Other elements here --> <div id="copyright"> Copyright Foo web designs </div> </div> I would like #cop......

富含淀粉
今天
10
0
Distinct()与lambda? - Distinct() with lambda?

问题: Right, so I have an enumerable and wish to get distinct values from it. 是的,所以我有一个可枚举的,并希望从中获得不同的值。 Using System.Linq , there's of course an ext......

法国红酒甜
今天
16
0
学习编写编译器[关闭] - Learning to write a compiler [closed]

问题: Preferred languages : C/C++, Java, and Ruby. 首选语言 :C / C ++,Java和Ruby。 I am looking for some helpful books/tutorials on how to write your own compiler simply for......

技术盛宴
今天
17
0
OSChina 周一乱弹 —— 毛巾又怎么样?!我在乎的是大姐姐温柔的怀抱!

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @薛定谔的兄弟 :分享洛神有语创建的歌单「我喜欢的音乐」: 《雨 因你而下,于你而止》- Seto 手机党少年们想听歌,请使劲儿戳(这里) @Dan...

小小编辑
今天
54
2

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部