iOS 设计模式的应用 ⑫ 迭代器

前言

    每次从自动售货机买汽水的时候,顾客投几个硬币进去,选择想要的汽水,然后它就被送到出货托盘。售货机中至少有两个主要部件在完成这个工作:

  • 容纳一堆汽水的内部货架
  • 从一堆汽水中取出下一瓶的分配器

    在面向对象软件中,内部货架就像是一个集合,有多种分配器可以枚举数据结构中的数据,也就是发放内部货架中的瓶子,这种针对抽象集合迭代行为的设计模式就叫做迭代器

什么是迭代器

    迭代器提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。遍历集合中元素的职能从集合本身转移到迭代器对象,其提供了一个用于访问集合元素并记录当前元素的接口,不同的迭代器可以执行不同的遍历策略。

List与ListIterator之间关系的类图.png

    List 定义了修改集合以及返回集合中元素个数的方法。ListIterator 保持让一个对 List 对象的引用,以便迭代器遍历结构元素中的元素并将其返回。ListIterator 定义了让客户端从迭代过程中访问下一项的方法。迭代器中有个内部的 _index 变量,记录集合中的当前位置。

外部迭代器和内部迭代器

外部迭代器 内部迭代器
外部迭代器让客户端直接操作迭代过程,所以客户端需要知道外部迭代器才能使用。但是它为客户端提供了更多的控制。 客户端不需要知道任何外部迭代器,而是可以通过集合对象的特殊接口,或者一次访问同一个元素,或者向集合中的每个元素发送消息。
客户端创建并维护外部迭代器 集合对象本身创建并维护它的外部迭代器
客户端可以使用不同外部迭代器实现多种类型的遍历 集合对象可以在不修改客户端代码的情况下,选择不同的外部迭代器

什么时候使用迭代器

  • 需要访问组合对象的内容,而不暴露其内部表示

  • 需要通过多种方式遍历组合对象

  • 需要提供一个统一的接口,用来遍历各种类型的组合对象

迭代器的优缺点

迭代器的优点

  1. 它支持以不同的方式遍历一个聚合对象。
  2. 迭代器简化了聚合类。
  3. 在同一个聚合上可以有多个遍历。
  4. 在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码。

迭代器的缺点

    由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。

Cocoa 中的迭代器实现

NSEnumerator

Foundation 框架中的 NSEnumerator 实现了迭代器模式。抽象NSEnumerator类的私有具体子类返回枚举器对象,这些对象依次遍历各种类型的集合——数组、集合、字典(值和键)——将集合中的对象返回给客户端。

集合类,如NSArrayNSSet和 ,NSDictionary 定义了返回适合集合类型的 NSEnumerator 子类实例的方法。所有枚举器都以相同的方式工作,可以在循环中向枚举器对象发送一条 nextObject 消息,从枚举器取得对象,该循环在nil返回时退出。

  • NSEnumerator 的使用

    NSArray *array  = @[@"instance1",@"instance2",@"instance3"];
    NSEnumerator *itemEnumerator = [array objectEnumerator];
    NSString *item;
    while (item = [itemEnumerator nextObject]) {
        NSLog(@"%@",item);
    }
    
  • 基于 Block 的枚举器

    NSArray *array  = @[@"instance1",@"instance2",@"instance3"];
    [array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            NSLog(@"%@",obj);
    }];
    
  • GNUStep 中的 NSArrayEnumerator 实现
    GNUStepNSArrayEnumerator 实现如下,每次对索引 pos++,通过 objectAtIndex 实现每次调用 nextObject 获取下一个对象。

    oaiSel = @selector(c:);
    countSel = @selector(count);
    
    - (id) initWithArray: (NSArray*)anArray
    {
      self = [super init];
      if (self != nil)
        {
          array = anArray;
          pos = 0;
          get = [array methodForSelector: oaiSel];
          cnt = (unsigned (*)(NSArray*, SEL))[array methodForSelector: countSel];
        }
      return self;
    }
    
    /**
     * Returns the next object in the enumeration or nil if there are no more
     * objects.
    * NB. modifying a mutable array during an enumeration can break things ... * don't do it. */ - (id) nextObject { if (pos >= (*cnt)(array, countSel)) return nil; return (*get)(array, oaiSel, pos++); }

快速枚举

    快速枚举是 Objective-C 2.0 中引入的一种语言特性,它提供了一种简洁的语法来有效地枚举集合,比传统使用 NSEnumerator 对象来遍历数组、集合和字典要快得多。
    要想使用快速枚举,需要实现 协议。Foundation 集合类—— NSArrayNSDictionary、 和 NSSet,以及 NSEnumerator 类都实现了协议,支持快速枚举。

NSArray *array  = @[@"instance1",@"instance2",@"instance3"];
for (NSString * item in array)
{
   NSLog(@"%@",item);
}

内部枚举

     NSArray 有个实例方法 makeObjectsPerformSelector:,它允许客户端向数组中每个元素发送一个消息,让其执行指定的 aSelector(必须实现了该方法)。

总结

    迭代器模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明地访问集合内部的数据。

你可能感兴趣的:(iOS 设计模式的应用 ⑫ 迭代器)