一、迭代器模式
1、什么是迭代器模式?
提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示。迭代器是 iOS 中运用的最多的模式之一,你用到的NSArray``NSDictionary``NSSet
等都是迭代器模式的实现,是 iOS 已经完整实现了的。如果你有详细的翻一下它们存在的属性的话,应该会注意到有一个属性叫objectEnumerator
和reverseObjectEnumerator
它们就是具体的迭代器,通过next
顺序访问。举个例子:
// 1. 数组集合
NSArray *data = @[@"1",@"2",@"3",@"4"];
// 2.创建迭代器
NSEnumerator *enumerator = [data objectEnumerator];
// 3.访问每一个元素
id obj = nil;
while (obj = [enumerator nextObject]) {
NSLog(@"---%@",obj);
}
2、迭代器的设计
迭代器就好比是遥控器选台。电视的所有台就是个集合类,而遥控器就是迭代器。
要写迭代器,首先要有一个集合类(线性表),创建集合类LinkedList(线性链表)需要先创建节点Node,最后才能创建迭代器LinkedIterator,下图是线性表:
节点类
Node.h
#import <Foundation/Foundation.h>
@interface Node : NSObject
// 指向下一个节点(链表中的指针)
@property (nonatomic, strong) Node *nextNode;
// 节点里面的data
@property (nonatomic, strong) id data;
// 节点数据
+ (instancetype)nodeData:(id)data;
@end
Node.m
#import "Node.h"
@implementation Node
+ (instancetype)nodeData:(id)data {
Node *node = [[self alloc] init];
node.data = data;
return node;
}
@end
线性链表类
LinkedList.h
#import <Foundation/Foundation.h>
#import "Node.h"
@interface LinkedList : NSObject
@property (nonatomic, strong) Node *headNode; /**< 头结点 */
/**
链表中的节点数
*/
@property (nonatomic, assign) NSInteger numberOfNode;
- (void)addData:(id)data; /**< 节点上的数据 */
@end
LinkedList.m
#import "LinkedList.h"
@implementation LinkedList
- (instancetype)init
{
self = [super init];
if (self) {
self.headNode = [Node new];
}
return self;
}
- (void)addData:(id)data {
// 1. 头节点为空,就添加
if (self.headNode == nil) {
self.headNode = [Node nodeData:data];
} else {
[self addData:data node:self.headNode];
}
// 数量的增加
self.numberOfNode++;
}
// 2. 有头结点了,就插入到下一个节点
- (void)addData:(id)data node:(Node *)node {
if (node.nextNode == nil) {
node.nextNode = [Node nodeData:data];
} else {
// 当下一个节点也有值了,进行递归调用
[self addData:data node:node.nextNode];
}
}
@end
迭代器类
IteratorProtocol.h
#import <Foundation/Foundation.h>
@protocol IteratorProtocol <NSObject>
// 下一个对象
- (id)nextObject;
@end
LinkedIterator.h
#import <Foundation/Foundation.h>
#import "LinkedList.h"
#import "IteratorProtocol.h"
@interface LinkedIterator : NSObject <IteratorProtocol>
// 迭代器的实现方法
+ (instancetype)linkedObjectIterator:(LinkedList *)linkedList;
@end
LinkedIterator.m
#import "LinkedIterator.h"
@interface LinkedIterator ()
@property (nonatomic, strong) LinkedList *linkedList;
@property (nonatomic, strong) Node *currentNode;
@end
@implementation LinkedIterator
+ (instancetype)linkedObjectIterator:(LinkedList *)linkedList {
// 1.初始化迭代器
LinkedIterator *linkedIterator = [[LinkedIterator alloc] init];
// 2. 保存链表数据
linkedIterator.linkedList = linkedList;
linkedIterator.currentNode = linkedList.headNode;
return linkedIterator;
}
- (id)nextObject {
self.currentNode = self.currentNode.nextNode;
return self.currentNode;
}
@end
对迭代器进行应用
ViewController.m
// 1.创建集合类
self.list = [[LinkedList alloc] init];
[self.list addData:@"A"];
[self.list addData:@"B"];
[self.list addData:@"C"];
// 2.迭代器的创建
LinkedIterator *linkedIterator = [LinkedIterator linkedObjectIterator:self.list];
// 3.访问每一个元素
Node *node = nil;
while (node = [linkedIterator nextObject]) {
NSLog(@"---%@",node.data);
}
3、深层处应用
能够遍历类的私有属性。demo如下:
IteratorProtocol.h
#import <Foundation/Foundation.h>
@protocol IteratorProtocol <NSObject>
// 下一个对象
- (id)nextObject;
// 重置迭代器指针
- (void)resetIterator;
@end
TZView.h
#import <UIKit/UIKit.h>
#import "IteratorProtocol.h"
@interface TZView : UIView <IteratorProtocol>
@end
TZView.m
#import "TZView.h"
#import "LinkedList.h"
@interface TZView ()
@property (nonatomic, strong) UIButton *tzBtn;
@property (nonatomic, strong) UILabel *tzLabel;
@property (nonatomic, strong) UITextField *tzTextField;
@property (nonatomic, strong) LinkedList *linkedList;
@property (nonatomic, strong) Node *currentNode;
@end
@implementation TZView
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
self.tzBtn = [[UIButton alloc] initWithFrame:self.bounds];
self.tzLabel = [[UILabel alloc] initWithFrame:self.bounds];
self.tzTextField = [[UITextField alloc] initWithFrame:self.bounds];
[self addSubview:self.tzBtn];
[self addSubview:self.tzLabel];
[self addSubview:self.tzTextField];
// 初始化
self.linkedList = [[LinkedList alloc] init];
[self.linkedList addData:self.tzBtn];
[self.linkedList addData:self.tzLabel];
[self.linkedList addData:self.tzTextField];
self.currentNode = self.linkedList.headNode;
}
return self;
}
#pragma mark - IteratorProtocol
- (id)nextObject {
self.currentNode = self.currentNode.nextNode;
return self.currentNode;
}
- (void)resetIterator {
self.currentNode = self.linkedList.headNode;
}
@end
ViewController.m
#import "ViewController.h"
#import "TZView.h"
#import "Node.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
TZView *view = [[TZView alloc] initWithFrame:self.view.bounds];
Node *node = nil;
[view resetIterator];
while (node = [view nextObject]) {
NSLog(@"%@", node.data);
}
[view resetIterator];
while (node = [view nextObject]) {
NSLog(@"%@", node.data);
}
}
@end
二、组合模式
1、什么是组合模式
组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。
2、组合模式用在什么地方
- 在程序中有树形结构的时候使用
- 忽略组合对象与单个对象的不同,进行统一处理的时候。
UIView 对于两者都符合,结构上属于树形结构,不管是 view 还是他的 subView 都可以进行默认的处理。
3、组合模式的使用
- 创建类,定义添加、移除和检索所有节点的方法
- 创建数组,实现添加等方法。
在这里,我暂时把枝节点和叶结点的实现合为一体,在数组个数中做判断,个数为 0 的即位叶结点。
4、demo
创建节点类Node,定义添加、移除和检索所有节点的方法
Node.h
#import <Foundation/Foundation.h>
@interface Node : NSObject
// 节点名字
@property (nonatomic, copy) NSString *nodeName;
// 子节点集合
@property (nonatomic, strong) NSMutableArray<Node *> *childNode;
// 初始化
+ (instancetype)nodeWithNodeName:(NSString *)nodeName;
// 添加子节点
- (void)addNode:(Node *)node;
// 删除子节点
- (void)removeNode:(Node *)node;
// 获取子节点
- (Node *)nodeAtIndex:(NSInteger)index;
// 打印Node
- (void)operation;
@end
Node.m
#import "Node.h"
@implementation Node
- (instancetype)init
{
self = [super init];
if (self) {
self.childNode = [NSMutableArray array];
}
return self;
}
// 初始化
+ (instancetype)nodeWithNodeName:(NSString *)nodeName {
Node *node = [[[self class] alloc] init];
node.nodeName = nodeName;
return node;
}
// 添加子节点
- (void)addNode:(Node *)node {
[self.childNode addObject:node];
}
// 删除子节点
- (void)removeNode:(Node *)node {
[self.childNode removeObject:node];
}
// 获取子节点
- (Node *)nodeAtIndex:(NSInteger)index {
if (index >= self.childNode.count) {
return nil;
} else {
return self.childNode[index];
}
}
// 打印Node
- (void)operation {
NSLog(@"nodeName = %@", self.nodeName);
}
- (NSString *)description {
return [NSString stringWithFormat:@"node - %@",self.nodeName];
}
@end
ViewController.m
#import "ViewController.h"
#import "Node.h"
@interface ViewController ()
// 根节点
@property (nonatomic, strong) Node *rootNode;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 创建根节点
self.rootNode = [Node nodeWithNodeName:@"A"];
// 创建第一级字节点
Node *b = [Node nodeWithNodeName:@"B"];
[self.rootNode addNode:b];
Node *c = [Node nodeWithNodeName:@"C"];
[self.rootNode addNode:c];
Node *d = [Node nodeWithNodeName:@"D"];
[self.rootNode addNode:d];
// 创建第二级子节点
[c addNode:[Node nodeWithNodeName:@"E"]];
[c addNode:[Node nodeWithNodeName:@"F"]];
[self.rootNode removeNode:b];
NSLog(@"%@", c.childNode);
NSLog(@"---%@", self.rootNode.childNode);
}
@end
打印结果:
2019-02-07 12:48:04.641707+0800 TreeDemo2[3428:358320] (
"node - E",
"node - F"
)
2019-02-07 12:48:04.641888+0800 TreeDemo2[3428:358320] ---(
"node - C",
"node - D"
)
5、优缺点
优点:
1、组合模式解耦了程序和各元素内部结构,可以把复杂的程序像单个接口一样处理该程序
2、高层模块调用简单
3、节点自由增加
缺点:
1、违反了依赖倒置原则,而接口不应该依赖于具体的实现类。比如树形的结构的时候,其叶子和树叶的声明都是实现类。