前言
????每次從自動售貨機買汽水的時候,顧客投幾個硬幣進去,選擇想要的汽水,然后它就被送到出貨托盤。售貨機中至少有兩個主要部件在完成這個工作:
- 容納一堆汽水的內部貨架
- 從一堆汽水中取出下一瓶的分配器
????在面向對象軟件中,內部貨架就像是一個集合,有多種分配器可以枚舉數據結構中的數據,也就是發放內部貨架中的瓶子,這種針對抽象集合迭代行為的設計模式就叫做迭代器。
什么是迭代器
????迭代器提供一種方法順序訪問一個聚合對象中各個元素, 而又無須暴露該對象的內部表示。遍歷集合中元素的職能從集合本身轉移到迭代器對象,其提供了一個用于訪問集合元素并記錄當前元素的接口,不同的迭代器可以執行不同的遍歷策略。
????List
定義了修改集合以及返回集合中元素個數的方法。ListIterator
保持讓一個對 List
對象的引用,以便迭代器遍歷結構元素中的元素并將其返回。ListIterator
定義了讓客戶端從迭代過程中訪問下一項的方法。迭代器中有個內部的 _index
變量,記錄集合中的當前位置。
外部迭代器和內部迭代器
外部迭代器 | 內部迭代器 |
---|---|
外部迭代器讓客戶端直接操作迭代過程,所以客戶端需要知道外部迭代器才能使用。但是它為客戶端提供了更多的控制。 | 客戶端不需要知道任何外部迭代器,而是可以通過集合對象的特殊接口,或者一次訪問同一個元素,或者向集合中的每個元素發送消息。 |
客戶端創建并維護外部迭代器 | 集合對象本身創建并維護它的外部迭代器 |
客戶端可以使用不同外部迭代器實現多種類型的遍歷 | 集合對象可以在不修改客戶端代碼的情況下,選擇不同的外部迭代器 |
什么時候使用迭代器
需要訪問組合對象的內容,而不暴露其內部表示
需要通過多種方式遍歷組合對象
需要提供一個統一的接口,用來遍歷各種類型的組合對象
迭代器的優缺點
迭代器的優點
- 它支持以不同的方式遍歷一個聚合對象。
- 迭代器簡化了聚合類。
- 在同一個聚合上可以有多個遍歷。
- 在迭代器模式中,增加新的聚合類和迭代器類都很方便,無須修改原有代碼。
迭代器的缺點
????由于迭代器模式將存儲數據和遍歷數據的職責分離,增加新的聚合類需要對應增加新的迭代器類,類的個數成對增加,這在一定程度上增加了系統的復雜性。
Cocoa 中的迭代器實現
NSEnumerator
Foundation
框架中的 NSEnumerator
實現了迭代器模式。抽象NSEnumerator
類的私有具體子類返回枚舉器對象,這些對象依次遍歷各種類型的集合——數組、集合、字典(值和鍵)——將集合中的對象返回給客戶端。
集合類,如NSArray
、NSSet
和 ,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
實現
GNUStep 中NSArrayEnumerator
實現如下,每次對索引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 集合類—— NSArray
、NSDictionary
、 和 NSSet
,以及 NSEnumerator
類都實現了協議,支持快速枚舉。
NSArray *array = @[@"instance1",@"instance2",@"instance3"];
for (NSString * item in array)
{
NSLog(@"%@",item);
}
內部枚舉
???? NSArray
有個實例方法 makeObjectsPerformSelector:
,它允許客戶端向數組中每個元素發送一個消息,讓其執行指定的 aSelector
(必須實現了該方法)。
總結
????迭代器模式就是分離了集合對象的遍歷行為,抽象出一個迭代器類來負責,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明地訪問集合內部的數據。