聲明:原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處撒妈。http://www.reibang.com/p/23e88dfe593b
設(shè)計(jì)模式系列:
30分鐘學(xué)透設(shè)計(jì)模式1-單例模式的前世今生
30分鐘學(xué)透設(shè)計(jì)模式2-隨處可見的Builder模式
30分鐘學(xué)透設(shè)計(jì)模式3-使用最多的Iterator模式
30分鐘學(xué)透設(shè)計(jì)模式4-最簡(jiǎn)單的面向接口編程-簡(jiǎn)單工廠模式
30分鐘學(xué)透設(shè)計(jì)模式5-從代理模式到AOP
一知纷、栗子
先從一個(gè)簡(jiǎn)單的栗子說(shuō)起,有一個(gè)ArrayList
需要遍歷屠缭,通常怎么去做呢悟狱?
List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
// 方法 1: foreach
for (String s : list) {
System.out.println(s);
}
// 方法 2: for循環(huán)
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
// 方法 3: 迭代器
Iterator it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
這里我們不討論這三種方法的效率,但是這幾種肯定我們經(jīng)常使用的磷籍。
1适荣、但是现柠,如下,在我們將List換成了Set之后弛矛,如果盡量不修改代碼的話够吩,這三種遍歷方式有什么變化呢?
Set<String> set = new HashSet<String>(Arrays.asList("a", "b", "c"));
結(jié)論:只有方法1和方法3是可用的丈氓,因?yàn)镾et不是順序結(jié)構(gòu)周循,不能采用for循環(huán)的方式遍歷。
2万俗、進(jìn)一步湾笛,如下,在我們繼續(xù)將Set換成Map之后闰歪,那現(xiàn)在遍歷方法會(huì)怎么樣呢嚎研?
Map<String, String> map = new HashMap<String, String>();
結(jié)論:方法1和3均可用,但是需要稍微修改一點(diǎn)库倘。
// 方法 1
for (Map.Entry<String, String> entry: map.entrySet()) {
System.out.println(entry.toString());
}
// 方法 3
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
for each這種方式遍歷的對(duì)象必須是一個(gè)數(shù)組或者是一個(gè)實(shí)現(xiàn)了Iterator接口的對(duì)象临扮。
無(wú)論存儲(chǔ)結(jié)構(gòu)怎么變,發(fā)現(xiàn)第三種遍歷方式教翩,都沒有什么變化杆勇。這就是我們將要介紹的迭代器(Iterator)模式。
二饱亿、迭代器模式定義
1蚜退、定義
迭代器模式就是提供一種方法順序訪問一個(gè)聚合對(duì)象中的各個(gè)元素,而不用暴露其內(nèi)部實(shí)現(xiàn)彪笼。在實(shí)際的開發(fā)過(guò)程中钻注,我們可能需要針對(duì)不同的需求,以不同的方式來(lái)遍歷集合對(duì)象杰扫,但不希望在集合對(duì)象的抽象接口層中充斥著各種不同的遍歷操作队寇。
通俗的講膘掰,迭代器為集合(如Collection章姓、List、Set识埋、Map等)提供了統(tǒng)一遍歷接口凡伊,提高代碼復(fù)用性,并隱藏其內(nèi)部實(shí)現(xiàn)窒舟。
2系忙、優(yōu)點(diǎn)
- 簡(jiǎn)化遍歷方式,不僅可以對(duì)數(shù)組惠豺、有序表進(jìn)行遍歷银还,對(duì)Map等結(jié)構(gòu)亦可风宁。
- 可提供多種遍歷方法。如對(duì)數(shù)組提供正序蛹疯、逆序的迭代器戒财。
- 迭代器簡(jiǎn)化了聚合類,而且封裝性強(qiáng)捺弦,用戶只需要得到迭代器就可以遍歷饮寞,而不需要額外關(guān)注遍歷算法。迭代器模式是“單一職責(zé)原則”的完美體現(xiàn)列吼。
3幽崩、缺點(diǎn)
由于迭代器模式將存儲(chǔ)數(shù)據(jù)和遍歷數(shù)據(jù)的職責(zé)分離,增加新的聚合類需要對(duì)應(yīng)增加新的迭代器類寞钥,類的個(gè)數(shù)成對(duì)增加慌申,這在一定程度上增加了系統(tǒng)的復(fù)雜性。
4凑耻、使用場(chǎng)景
- 訪問一個(gè)聚合對(duì)象的內(nèi)容而無(wú)須暴露它的內(nèi)部表示太示。
- 需要為聚合對(duì)象提供多種遍歷方式。
- 為遍歷不同的聚合結(jié)構(gòu)提供一個(gè)統(tǒng)一的接口香浩。
三类缤、實(shí)現(xiàn)一個(gè)簡(jiǎn)單的迭代器
1、定義Iterator接口
public interface Iterator {
Object next();
boolean hasNext();
}
2邻吭、定義集合Container接口(類似List)
public interface Container {
void add(Object obj);
Iterator createIterator();
}
3餐弱、定義具體的集合類ConcreteContainer(類似ArrayList)
public class ConcreteContainer implements Container {
private List<Object> list;
public ConcreteContainer(List<Object> list) {
this.list = list;
}
public void add(Object obj) {
list.add(obj);
}
public Iterator createIterator() {
return new ConcreteIterator();
}
private class ConcreteIterator implements Iterator {
private int cursor;
public Object next() {
if (hasNext()) {
return list.get(cursor++);
}
return null;
}
public boolean hasNext() {
return cursor != list.size();
}
}
}
4、測(cè)試類
經(jīng)過(guò)上面三個(gè)步驟囱晴,我們已經(jīng)完成了一個(gè)簡(jiǎn)單版的迭代器膏蚓。下面我們測(cè)試下及遍歷功能。
public static void main(String[] args) {
Container container = new ConcreteContainer(new ArrayList<Object>());
container.add("a");
container.add("b");
container.add("c");
Iterator iterator = container.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}