行为型模式之迭代器模式

提供一种方法顺序访问一个聚合对象中的各个元素,而不需要暴露该对象的内部表示
所谓聚合:指一组对象的组合结构,比如集合,数组等

公交车上,有各色各样的人,售票员都需要让这些人买票,那么要让这些人买票,售票员肯定都得把车厢里的人都遍历一遍,不放过一个不买票的乘客,不管这个人是中国人还是外国人,是公交车公司内部人员还是公务员或者是小偷等,只要是来乘车的乘客,就必须买票.

同样的道理.当你需要访问一个聚集对象,而且不管这些对象是什么都需要遍历的时候,你就应该考虑用迭代器模式另外,售票员从车头到车尾来售票,也可以从车尾到车头售票,也就是说,你需要对聚集有多种方式遍历时,可以考虑用迭代器模式由于不管乘客是什么,售票员的做法始终是相同的,都是从第一个开始,下一个是谁,是否结束,当前售到哪一个人了,这些方法每天他都在做,也就是说,为遍历不同的聚集结构提供如开始,下一个,是否结束,当前哪一项等统一的接口

仔细分析上面的问题,要以一个统一的方式来访问内部实现不同的聚合对象,那么首先就需要把这个统一的访问方式定义出来,按照这个统一的访问方式定义出来的接口,在迭代器模式中对应的就是Iterator接口。

迭代器迭代的是具体的聚合对象,那么不同的聚合对象就应该有不同的迭代器,为了让迭代器以一个统一的方式来操作聚合对象,因此给所有的聚合对象抽象出一个公共的父类,让它提供操作聚合对象的公共接口,这个抽象的公共父类在迭代器模式中对应的就是Aggregate对象

接下来就该考虑如何创建迭代器了,由于迭代器和相应的聚合对象紧密相关,因此让具体的聚合对象来负责创建相应的迭代器对象。

模式结构与说明

在这里插入图片描述

抽象容器:一般是一个借口,提供一个iterator()方法
具体容器:就是抽象容器的具体实现类,比如List接口的有序列表实现
抽象迭代器:定义遍历元素所需要的方法,一般来说会有这么几个方法:取得第一个元素的方法first(),取得下一个元素的方法next(),判断是否遍历结束的方法isDone()(或者叫hasNext()),移出当前对象的方法remove()。
迭代器实现:实现迭代器接口中定义的方法,完成集合的迭代器

说到抽象迭代器的这些方法,这里大家是不是感觉很熟悉,数据结构里的线性表,单链表等就有这些特性呢

线性表

线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其他数据元素都是收尾相接的
种类:链表,栈,队列

在这里插入图片描述
在这里插入图片描述

示例实现

  1. 先定义聚合对象里的元素对象
@interface Node : NSObject
/*指向下一个节点*/
@property (nonatomic,strong) Node *nextNode;
/*挂载的对象*/
@property (nonatomic,strong) id item;
//构造方法
+ (instancetype)nodeWithItem:(id)item;

@end
+ (instancetype)nodeWithItem:(id)item
{
    Node *node = [[[self class] alloc] init];
    node.item = item;
    return node;
}
  1. 定义聚合对象(提供公共接口)
@interface LinkList : NSObject
/*头结点*/
@property (nonatomic,strong,readonly) Node *headNode;
/*有多少个节点*/
@property (nonatomic,readonly) NSInteger numberOfNodes;
//节点挂载对象
- (void)addItem:(id)item;

@end

@implementation LinkList
- (instancetype)init
{
    self = [super init];
    if (self) {
        self.headNode = [Node new];
    }
    return self;
}
- (void)addItem:(id)item
{
    if (self.headNode == nil) {
        self.headNode = [Node nodeWithItem:item];
    } else {
        [self addItem:item node:self.headNode];
    }
    self.numberOfNodes++;
}

- (void)addItem:(id)item node:(Node *)node
{
    if (node.nextNode == nil) {
        node.nextNode = [Node nodeWithItem:item];
    } else {
        [self addItem:item node:node.nextNode];
    }
}

@end
  1. 定义Iterator接口
@protocol IteratorProtocol <NSObject>

@required
//下一个对象
- (id)nextObject;
//重置
- (void)resetIterator;
//是否有下一个
- (BOOL)hasNext;
@end
  1. 定义Iterator对象(遵循IteratorProtocol协议)
@implementation LinkListIterator

+ (instancetype)linkListIteratorWithLinkList:(LinkList *)linkList
{
    LinkListIterator *iterator = [LinkListIterator new];
    iterator.linkList = linkList;
    iterator.currentNode = linkList.headNode;
    return iterator;
}


- (id)nextObject {
    self.currentNode = self.currentNode.nextNode;
    return self.currentNode;
}

- (void)resetIterator
{
    self.currentNode = self.linkList.headNode;
}

- (BOOL)hasNext
{
    return self.currentNode.nextNode ? YES : NO;
}

@end
  1. 客户端实践
    // 创建集合对象
    LinkList *list = [[LinkList alloc] init];
    [list addItem:@"A"];
    [list addItem:@"B"];
    [list addItem:@"C"];
    [list addItem:@"D"];
    
    
    LinkListIterator *iterator = [LinkListIterator linkListIteratorWithLinkList:list];
//    NSLog(@"%@",[iterator nextObject]);
    Node *node = nil;
    while (node = [iterator nextObject]) {
        NSLog(@"%@--%d",node.item,[iterator hasNext]);
//        if ([node.item isEqualToString:@"C"]) {
//            [iterator resetIterator];
//        }
    }

上面的示例只是实现了next,hanNext,大家同样可以试着去做pre,first,index等操作

在iOS 中的应用

  1. 数组迭代器
    NSArray *array = [NSArray arrayWithObjects:@"bei", @"jing", @"huan", @"ying", @"nin", nil];
    // 获取数组的正序迭代器
    NSEnumerator *enu1 = [array objectEnumerator];
    // 获取数组的反序迭代器
    NSEnumerator *enu2 = [array reverseObjectEnumerator];
    // 遍历数组
    id obj = nil;
    // 正序,获取下一个需要遍历的元素
    while (obj = [enu1 nextObject]) {
        NSLog(@"%@", obj);
    }
    // 反序,获取下一个需要遍历的元素
    while (obj = [enu2 nextObject]) {
        NSLog(@"%@", obj);
    }
  1. 集合迭代器
    NSSet *set = [NSSet setWithObjects:@5, @23, @3, @8, @21, @33, @18, nil];
    NSEnumerator *enu = [set objectEnumerator];
    id obj = nil;
    while (obj = [enu nextObject]) {
        NSLog(@"%@", obj);
    }
  1. 字典迭代器

    NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:@"value1", @"key1", @"value2", @"key2", nil];
    // key 迭代器
    NSEnumerator *keyEnumer = [dic keyEnumerator];
    id key = nil;
    while (key = [keyEnumer nextObject]) {
        NSLog(@"%@ = %@", key, [dic objectForKey:key]);
    }

模式讲解

迭代器模式的本质:控制访问聚合对象中的元素

优点:

  1. 可以提供多种遍历方式,比如说对有序列表,我们可以根据需要提供正序遍历,倒序遍历两种迭代器,用户用起来只需要得到我们实现好的迭代器,就可以方便的对集合进行遍历了
  2. 封装性良好,用户只需要得到迭代器就可以遍历,而对于遍历算法则不用去关心。
  3. 同一个聚合上可以有多个遍历
    每个迭代器保持它自己的遍历状态,比如前面实现中的迭代索引位置,因此可以对同一个聚合对象同时进行多个遍历

缺点:

对于比较简单的遍历(像数组或者有序列表),使用迭代器方式遍历较为繁琐

Demo地址

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值