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


    原型模式概念:

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

    原型模式定义:

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

    原型模式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项目下。
  • 相关阅读:
    解决“Dynamic Web Module 3.0 requires Java 1.6 or newer.”错误
    React中使用Ant Table组件
    Maven在Eclipse中的实用小技巧
    knockout+echarts实现图表展示
    深入分析Spring 与 Spring MVC容器
    二维码登录原理及生成与解析
    Maven中安装本地Jar包到仓库中或将本地jar包上传
    sorl6.0+jetty+mysql搭建solr服务
    git revert和reset区别
    java注意的一些细节问题
  • 原文地址:https://www.cnblogs.com/zhou--fei/p/10659556.html
Copyright © 2020-2023  润新知