定義:
迭代器模式又叫做游標(Cursor)模式。提供一種方法訪問一個容器(container)對象中的各個元素,而又不暴露該對象的內部細節
迭代器模式的結構:
抽象容器:一般是一個接口,提供一個iterator()方法,例如java中的Collection接口,List接口,Set接口等。
具體容器:就是抽象容器的具體實現類,比如List接口的有序列表實現ArrayList,List接口的鏈表實現LinkList,Set接口的哈希列表的實現HashSet等。
抽象迭代器:定義遍歷元素所需要的方法,一般來說會有這麼幾個方法:取得第一個元素的方法first(),取得下一個元素的方法next(),判斷是否遍歷結束的方法isDone()(或者叫hasNext()),移出當前對象的方法remove()。
迭代器實現:實現迭代器接口中定義的方法,完成集合的迭代器。
類圖:
代碼示例:
迭代器接口
interface Iterator { public Object next(); public boolean hasNext(); }
迭代器的實現
class ConcreteIterator implements Iterator{ private List list = new ArrayList(); private int cursor = 0; public ConcreteIterator(List list){ this.list = list; } public boolean hasNext() { if(cursor==list.size()){ return false; } return true; } public Object next() { Object obj = null; if(this.hasNext()){ obj = this.list.get(cursor++); } return obj; } }
容器接口
interface Aggregate { public void add(Object obj); public void remove(Object obj); public Iterator iterator(); }
容器的實現
class ConcreteAggregate implements Aggregate { private List list = new ArrayList(); public void add(Object obj) { list.add(obj); } public Iterator iterator() { return new ConcreteIterator(list); } public void remove(Object obj) { list.remove(obj); } }
客戶端代碼
public class Client { public static void main(String[] args){ Aggregate ag = new ConcreteAggregate(); ag.add("小明"); ag.add("小紅"); ag.add("小剛"); Iterator it = ag.iterator(); while(it.hasNext()){ String str = (String)it.next(); System.out.println(str); } } }
深入理解:
就是把遍歷算法從容器對象中獨立出來,為什麼要把遍歷算從容器對象中獨立出來呢? 因為在面向對象設計中,一個難點就是辨認對象的職責。理想的狀態下,一個類應該只有一個單一的職責。職責分離可以最大限度的去耦合,但是職責單一說起來容易,做起來難。具體到本模式,我們明顯可以看到,一個容器對象它提供了兩個職責:一是組織管理數據對象,二是提供遍歷算法。
所以:Iterator模式就是分離了集合對象的遍歷行為,抽象出一個迭代器類來負責,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明的訪問集合內部的數據。
下面來看看java中部分迭代器的使用:
java中迭代器接口
public interface Iterator { boolean hasNext();//判斷是否存在下一個對象元素 E next(); void remove(); }
測試Iterator
import java.util.*; public class TestIterator { public static void main(String[] args) { List list = new ArrayList(); Map map = new HashMap(); for(int i = 0;i < 10 xss=removed xss=removed iterMap=map.entrySet().iterator(); xss=removed> list=new ArrayList (); for(int i=0;i<10;i++){ list.add(new String("list"+i) ); } for(String str:list){ System.out.println(str); } }
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); }
//2.集合迭代器 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); }
//3.字典迭代器 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]); }
// 對象迭代器 NSEnumerator *objEnumer = [dic objectEnumerator]; id obj = nil; while (obj = [objEnumer nextObject]) { NSLog(@"%@", obj); }
下面是比較常用的用法
//快速遍歷 NSArray *array = @[@"張三", @"李四", @"王五"]; for (id item in array) { NSLog(@"item is :%@", item); }
//基於塊的枚舉 //數組 NSArray *array = @[@"張三", @"李四", @"王五"]; NSString *str = @"李四"; [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"item is :%@", obj); if ([obj localizedStandardCompare:str] == NSOrderedSame) { *stop = YES; NSLog(@"停止遍歷"); } }]; //字典 NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:@"value1", @"key1", @"value2", @"key2", nil]; [dic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { NSLog(@"item is :%@", obj); }]; //set NSSet *set = [NSSet setWithObjects:@5, @23, @3, @8, @21, @33, @18, nil]; [set enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) { NSLog(@"%@", obj); }];
迭代器模式的優缺點
迭代器模式的優點有:
1. 簡化了遍歷方式,對於對象集合的遍歷,還是比較麻煩的,對於數組或者有序列表,我們尚可以通過游標來取得,但用戶需要在對集合了解很清楚的前提下,自行遍歷對象,但是對於hash表來說,用戶遍歷起來就比較麻煩了。而引入了迭代器方法後,用戶用起來就簡單的多了。
2. 可以提供多種遍歷方式,比如說對有序列表,我們可以根據需要提供正序遍歷,倒序遍歷兩種迭代器,用戶用起來只需要得到我們實現好的迭代器,就可以方便的對集合進行遍歷了。
3. 封裝性良好,用戶只需要得到迭代器就可以遍歷,而對於遍歷算法則不用去關心。
迭代器模式的缺點:
1. 對於比較簡單的遍歷(像數組或者有序列表),使用迭代器方式遍歷較為繁瑣,大家可能都有感覺,像ArrayList,我們寧可願意使用for循環和get方法來遍歷集合。
迭代器模式的適用場景
1. 迭代器模式是與集合共生共死的,一般來說,我們只要實現一個集合,就需要同時提供這個集合的迭代器,就像java中的Collection,List、Set、Map等,這些集合都有自己的迭代器。假如我們要實現一個這樣的新的容器,當然也需要引入迭代器模式,給我們的容器實現一個迭代器。
2. 但是,由於容器與迭代器的關系太密切了,所以大多數語言在實現容器的時候都給提供了迭代器,並且這些語言提供的容器和迭代器在絕大多數情況下就可以滿足我們的需要,所以現在需要我們自己去實踐迭代器模式的場景還是比較少見的,我們只需要使用語言中已有的容器和迭代器就可以了。
參考書籍
Objective-C編程之道