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.<br />
     * 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 對象來遍歷數組、集合和字典要快得多。
????要想使用快速枚舉,需要實現 <NSFastEnumeration> 協議。Foundation 集合類—— NSArrayNSDictionary、 和 NSSet,以及 NSEnumerator 類都實現了協議,支持快速枚舉。

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

內部枚舉

???? NSArray 有個實例方法 makeObjectsPerformSelector:,它允許客戶端向數組中每個元素發送一個消息,讓其執行指定的 aSelector(必須實現了該方法)。

總結

????迭代器模式就是分離了集合對象的遍歷行為,抽象出一個迭代器類來負責,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明地訪問集合內部的數據。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 《iOS設計模式解析》設計模式是面向對象編程中的概念,是一個對象或類的設計模板,用于解決特定領域經常發生的問題。 ...
    云中追月閱讀 601評論 0 1
  • 抽象工廠 抽象工廠模式提供了一個接口,用于創建相關或依賴對象的族,而不指定具體的類。 客戶與從工廠獲得的具體對象的...
    woshishui1243閱讀 3,367評論 1 5
  • 一、概念 1、迭代器模式的動機 ? 平時我們經常使用for循環直接對數據進行遍歷,但是如何對外提供遍歷的接口呢,...
    阿餅six閱讀 1,236評論 0 4
  • 文:饒志臻(簡書作者) iOS 中的 21 種設計模式 對象創建 原型(Prototype) 使用原型實例指定創建...
    sky007z閱讀 208評論 0 0
  • 在軟件工程中,(引自維基百科)設計模式[https://zh.wikipedia.org/wiki/%E8%AE%...
    jackyshan閱讀 39,793評論 7 204