在开发中,不同的场景适用不同的设计模式。对于开发建模方面,可以根据模型的抽象类型设计成简单属性模式和复杂组合模式。
因为组合模式中的属性为多种类型对象,可操作性也比较灵活。
而针对这种复杂数据结构,有两种设计模式可以使用:
1.组合模式
2.迭代器模式
 
组合模式篇
组合模式简介:
1.组合模式就是一个树形数据结构
2.对组合对象的查询,访问都是递归操作。
3.所有的节点都会实现同一套接口或者继承自 同一个抽象父类。
4.每个对象都是其中的一个节点,无论叶子节点和组件节点都有相同的接口。只是叶子节点的接口返回为空,组件节点的接口实现接口。
5.组合模式让我们把相同基类型的对象组合到树状结构中,其中父节点包含同类型的子节点
 
组合模式的对象图如下:
aComposite:组件节点,下面包含子节点
aLeaf:叶子节点,下面没有子节点。
 
组合模式的类图如下:

aComposite:组件节点中包含的动作如下:
1.基本操作
2.对子节点的各种操作(增,删,查)
 
aLeaf:叶子节点总包含的动作如下:
1.基本操作
因为叶子节点是最底层,最简单的节点,所以它所包含的动作也是最简单的,只有作用节点最基本的operation功能。
 
组合模式的作用:
1.将对象组合成树形结构,以表示“整体-部分”的层次结构
2.组合模式使得客户端对单个对象和组合对象的操作具有一致性。使客户端对组件节点和叶子节点进行处理时,能够对它们的区别无感知,好像它们都是同样的简单对象。
 
组合模式的实际使用例子:
线段轨迹这个抽象事物为例子,这个抽象例子中包含三种模型:
1.线段,它是一个组合模式模型,里面可以包含子线段,连接点,点。
2.连接点,它是线段(或子线段)中的内容连接部分。
3.点,只有一个点的线段或者长度为0的线段。
 
这三种抽象事物的类UML图如下:
 

这三种抽象事物的对象UML图如下:
 

代码实现如下:

 1.先定义这三个类所共同遵守的协议:Mark协议
@protocol Mark <NSObject,NSCopying>
@property (nonatomic, strong) UIColor *color;
@property (nonatomic, assign) CGSize size;
@property (nonatomic, assign) CGPoint location;
- (void)addMark:(id<Mark>)mark;
- (void)removeMark:(id<Mark>)mark;
- (void)removeAllMarks;
- (id<Mark>)childAtIndex:(int)index;
- (id<Mark>)lastChild;
- (NSUInteger)count;
@end

2.Stroke类实现Mark协议如下:

@interface Stroke()
@property (nonatomic, strong) NSMutableArray<id<Mark>> *markArray;
@end @implementation Stroke
@synthesize color,location,size;
#pragma mark - 属性操作
- (void)setLocation:(CGPoint)location {}
- (CGPoint)location {
if (_markArray.count) {
return [[_markArray firstObject] location];
} else {
return CGPointZero;
}
}
#pragma mark - Mark操作
- (NSMutableArray<id<Mark>> *)markArray {
if (!_markArray) {
_markArray = @[].mutableCopy;
}
return _markArray;
} - (void)addMark:(id<Mark>)mark {
[self.markArray addObject:mark];
} - (void)removeMark:(id<Mark>)mark {
//在当前节点中,就从当前节点删除,不在当前节点,就深度查找子节点
if ([_markArray containsObject:mark]) {
[self.markArray removeObject:mark];
} else {
[_markArray makeObjectsPerformSelector:@selector(removeMark:) withObject:mark];
}
} - (void)removeAllMarks {
[self.markArray removeAllObjects];
} - (id<Mark>)childAtIndex:(int)index {
if (self.markArray.count == ) {
return nil;
} else {
return self.markArray[index];
}
} - (id<Mark>)lastChild {
return self.markArray.lastObject;
} - (NSUInteger)count {
return self.markArray.count;
}
3.Vertex实现Mark协议如下:

@implementation Vertex
@synthesize location;
@dynamic color,size; - (instancetype)initWithLocation:(CGPoint)location {
self = [super init];
if (self) {
self.location = location;
}
return self;
} #pragma mark - 属性操作
- (UIColor *)color{return nil;}
- (void)setColor:(UIColor *)color{}
- (CGSize)size{return CGSizeZero;}
- (void)setSize:(CGSize)size{} #pragma mark - Mark操作
- (void)addMark:(id<Mark>)mark {}
- (void)removeMark:(id<Mark>)mark {}
- (void)removeAllMarks {}
- (id<Mark>)childAtIndex:(int)index {return nil;}
- (id<Mark>)lastChild {return nil;}
- (NSUInteger)count {return ;}

4.Dot类实现Mark协议如下:

@interface Dot : Vertex
@end @implementation Dot
@synthesize color,size;

因为Dot类基础自Vertex,所以对象Mark对象的操作使用父类的就好了

迭代器模式篇

迭代器模式简介:

1.迭代器提供了一种 顺序访问聚合对象(集合)中元素的方法,而无需暴露聚合对象(集合)的底层表示和结构细节。
2. 为聚合对象(集合)配置迭代器后,遍历集合元素的任务从集合 转移给了迭代器对象。
3.请问啥叫迭代器模式?
答:针对抽象集合的迭代行为 而采用的设计模式,叫做迭代器模式
 
迭代器模式的对象图如下:
 

简单表示,迭代器持有着聚合对象

 

标准表示:
1.抽象聚合体Aggregate中定义了创建迭代器的接口,实例聚合类ConcreteAggregate实现创建迭代器的接口,返回自己类型的迭代器。
2.抽象迭代器Iterator定义了通用迭代方法,实例迭代器ConcreteIterator实现迭代方法接口。
 
迭代器模式的种类:
1.外部迭代器
由聚合对象直接将自己的迭代器返回给调用者,调用者进行灵活使用,举例如下:
NSEnumerator *enumerator = [self enumerator];
id <Mark> mark;
while (mark = [enumerator nextObject]) {
[mark lastChild]
}
2.内部迭代器
由聚合体提供一个迭代接口,这个迭代接口中有一个参数,该参数需要传递一个供聚合体内部在遍历时调用的“代码块”。这样在
聚合体内部遍历时,就将每个对象执行传递过来的预先定义好的函数。
举例如下:

    self.stroke = [Stroke new];
[self.stroke enumerateMarksUsingBlock:^(id<Mark> mark, BOOL *stop) { }]

迭代器模式的实际使用例子:

现在继续使用刚才使用举的抽象事物“线段轨迹”
这个抽象例子中包含三种模型:线段,连接点,点。
 
 在Mark协议中定义迭代器接口,返回外部迭代器
 

代码实现如下:

Mark协议接口定义

@protocol Mark <NSObject,NSCopying>
@property (nonatomic, strong) UIColor *color;
@property (nonatomic, assign) CGSize size;
@property (nonatomic, assign) CGPoint location;
- (void)addMark:(id<Mark>)mark;
- (void)removeMark:(id<Mark>)mark;
- (void)removeAllMarks;
- (id<Mark>)childAtIndex:(int)index;
- (id<Mark>)lastChild;
- (NSUInteger)count;
- (instancetype)copy;
//迭代器
- (NSEnumerator *)enumerator;
@end;

Stroke类接口实现

@interface Stroke()
@property (nonatomic, strong) NSMutableArray<id<Mark>> *markArray;
@end @implementation Stroke
@synthesize color,location,size;
#pragma mark - 属性操作
- (void)setLocation:(CGPoint)location {}
- (CGPoint)location {
if (_markArray.count) {
return [[_markArray firstObject] location];
} else {
return CGPointZero;
}
}
#pragma mark - Mark操作
- (NSMutableArray<id<Mark>> *)markArray {
if (!_markArray) {
_markArray = @[].mutableCopy;
}
return _markArray;
} - (void)addMark:(id<Mark>)mark {
[self.markArray addObject:mark];
} - (void)removeMark:(id<Mark>)mark {
//在当前节点中,就从当前节点删除,不在当前节点,就深度查找子节点
if ([_markArray containsObject:mark]) {
[self.markArray removeObject:mark];
} else {
[_markArray makeObjectsPerformSelector:@selector(removeMark:) withObject:mark];
}
} - (void)removeAllMarks {
[self.markArray removeAllObjects];
} - (id<Mark>)childAtIndex:(int)index {
if (self.markArray.count == ) {
return nil;
} else {
return self.markArray[index];
}
} - (id<Mark>)lastChild {
return self.markArray.lastObject;
} - (NSUInteger)count {
return self.markArray.count;
} #pragma mark - 迭代器
- (NSEnumerator *)enumerator {
return [[ZHFMarkEnumerator alloc] initWithMark:self];
}
 在Mark协议中定义内部迭代器接口:
 
 

代码实现如下:

Mark协议接口定义
@protocol Mark <NSObject,NSCopying>
@property (nonatomic, strong) UIColor *color;
@property (nonatomic, assign) CGSize size;
@property (nonatomic, assign) CGPoint location;
- (void)addMark:(id<Mark>)mark;
- (void)removeMark:(id<Mark>)mark;
- (void)removeAllMarks;
- (id<Mark>)childAtIndex:(int)index;
- (id<Mark>)lastChild;
- (NSUInteger)count;
- (instancetype)copy;
//迭代器
- (NSEnumerator *)enumerator;
//内部迭代器
- (void)enumerateMarksUsingBlock:(void (^) (id <Mark> mark, BOOL *stop))block;
@end;
Stroke类接口实现

@interface Stroke()
@property (nonatomic, strong) NSMutableArray<id<Mark>> *markArray;
@end @implementation Stroke
@synthesize color,location,size;
#pragma mark - 属性操作
- (void)setLocation:(CGPoint)location {}
- (CGPoint)location {
if (_markArray.count) {
return [[_markArray firstObject] location];
} else {
return CGPointZero;
}
}
#pragma mark - Mark操作
- (NSMutableArray<id<Mark>> *)markArray {
if (!_markArray) {
_markArray = @[].mutableCopy;
}
return _markArray;
} - (void)addMark:(id<Mark>)mark {
[self.markArray addObject:mark];
} - (void)removeMark:(id<Mark>)mark {
//在当前节点中,就从当前节点删除,不在当前节点,就深度查找子节点
if ([_markArray containsObject:mark]) {
[self.markArray removeObject:mark];
} else {
[_markArray makeObjectsPerformSelector:@selector(removeMark:) withObject:mark];
}
} - (void)removeAllMarks {
[self.markArray removeAllObjects];
} - (id<Mark>)childAtIndex:(int)index {
if (self.markArray.count == ) {
return nil;
} else {
return self.markArray[index];
}
} - (id<Mark>)lastChild {
return self.markArray.lastObject;
} - (NSUInteger)count {
return self.markArray.count;
} #pragma mark - 迭代器
- (NSEnumerator *)enumerator {
return [[ZHFMarkEnumerator alloc] initWithMark:self];
} - (void)enumerateMarksUsingBlock:(void (^)(id<Mark>, BOOL *stop))block {
NSEnumerator *enumerator = [self enumerator];
id <Mark> mark;
BOOL *stop = NO;
for (id <Mark> mark in enumerator) {
block(mark, &stop);
if (stop) {
break;
}
}
}
熟练使用设计模式是编写高扩展,高稳定,高复用,三高代码很重要的一项技能。愿你我一同砥砺前行。
完整的项目代码地址如下:
目前项目还没有完全结束,处于持续完善中...
 

设计模式应用场景之Model设计中可以用到的设计模式的更多相关文章

  1. 《Android源代码设计模式解析》读书笔记——Android中你应该知道的设计模式

    断断续续的,<Android源代码设计模式解析>也看了一遍.书中提到了非常多的设计模式.可是有部分在开发中见到的几率非常小,所以掌握不了也没有太大影响. 我认为这本书的最大价值有两点,一个 ...

  2. Model设计中常见的技巧和注意事项

    verbose_name 可以作为第一个参数传入,书写更加工整和有序: name = models.CharField('类别名',default="", max_length=3 ...

  3. 设计模式——如何避免在OO设计中违反依赖倒置原则

    1 变量不可以包含具体类的引用.一旦new,就对具体类产生依赖,用工厂模式来避开. 2 类不要派生至具体类.用派生抽象类避开. 3 不要覆盖基类已经实现的方法.基类中已实现的方法应该由所有子类共享.

  4. [.net 面向对象程序设计深入](13)实战设计模式——设计模式使用场景及原则

    [.net 面向对象程序设计深入](13)实战设计模式——设计模式使用场景及原则 1,什么是设计模式? 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计 ...

  5. 设计模式,Let's “Go”! (中)

    * { color: #3e3e3e } body { font-family: "Helvetica Neue", Helvetica, "Hiragino Sans ...

  6. [.net 面向对象程序设计深入](18)实战设计模式——设计模式使用场景及原则

    [.net 面向对象程序设计深入](18)实战设计模式——设计模式使用场景及原则 1,什么是设计模式? 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计 ...

  7. PHP的设计模式及场景应用介绍

    有大量的文章解释什么是设计模式,如何实现设计模式,网络上不需要再写一篇这样的文章.相反,在本文中我们更多的讨论什么时候用和为什么要用,而不是用哪一个和如何使用. 我将会为这些设计模式描绘不同的场景和案 ...

  8. DDD设计中的Unitwork与DomainEvent如何相容?

    最近在开发过程中,遇到了一个场景,甚是棘手,在这里分享一下.希望大家脑洞大开一起来想一下解决思路.鄙人也想了一个方案拿出来和大家一起探讨一下是否合理. 一.简单介绍一下涉及的对象概念 工作单元:维护变 ...

  9. PHP中常见的五种设计模式

    设计模式只是为 Java架构师准备的 — 至少您可能一直这样认为.实际上,设计模式对于每个人都非常有用.如果这些工具不是 “架构太空人” 的专利,那么它们又是什么?为什么说它们在 PHP 应用程序中非 ...

随机推荐

  1. 执行计划--WHERE条件的先后顺序对执行计划的影响

    在编写SQL时,会建议将选择性高(过滤数据多)的条件放到WHERE条件的前面,这是为了让查询优化器优先考虑这些条件,减少生成最优(或相对最优)的执行计划的时间,但最终的执行计划生成过滤顺序还是决定这些 ...

  2. Tempdb--临时对象缓存

    SQL Server删除一个临时对象时,不移除该对象的条目,当再次使用时,就无须重新创建临时对象,SQL Server为临时对象缓存一个数据页和一个IAM页,并回收剩余页,如果临时表的大小超过8MB, ...

  3. R语言中Fisher判别的使用方法

    最近编写了Fisher判别的相关代码时,需要与已有软件比照结果以确定自己代码的正确性,于是找到了安装方便且免费的R.这里把R中进行Fisher判别的方法记录下来. 1. 判别分析与Fisher判别 不 ...

  4. Visifire图表

    引用DLL: WPFToolkit WPFVisifire.Charts.dll WPFVisifire.Gauges.dll 1.柱状图 代码: public void BindChart1() { ...

  5. TestNG学习笔记目录

    学习TestNG主要用于GUI自动化测试使用,学习目录随进度不断更新.文档内容主要是翻译官方doc,同时加入自己的理解和案例.如有理解偏差欢迎指正 一.TestNG Eclipse plug-in 安 ...

  6. 【12c OCP】CUUG OCP认证071考试原题解析(34)

    34.choose two View the Exhibit and examine the structure of the PRODUCT_INFORMATION and INVENTORIES ...

  7. python 取出字典的键或者值/如何删除一个字典的键值对/如何遍历字典

    先定义一个字典并直接进行初始化赋值 my_dict = dict(name="lowman", age=45, money=998, hourse=None) 1.取出该字典所有的 ...

  8. JAVA构造函数(方法)

    一.什么是构造函数 java构造函数,也叫构造方法,是java中一种特殊的函数.函数名与相同,无返回值. 作用:一般用来初始化成员属性和成员方法的,即new对象产生后,就调用了对象了属性和方法. 在现 ...

  9. 不信任的 .exe 怎么办,用 Windows 沙盒啊!

    简评:维基百科,在计算机安全领域,沙盒(sandbox)是种安全机制,为执行中的程式提供的隔离环境.通常是作为一些来源不可信.具破坏力或无法判定程序意图的程序提供实验之用. 微软正在尝试解决人们对运行 ...

  10. 官宣,PyTorch 1.0 稳定版本现已推出

    简评:快来一起快乐地学习吧. 随着 PyTorch 生态系统和社区继续为开发人员提供有趣的新项目和教育资源,今天(12 月 7日)在 NeurIPS 会议上发布了 PyTorch 1.0 稳定版.研究 ...