迭代器模式是數(shù)據(jù)訪問遍歷的一種行為模式。java中List、Set、Map 等都包含了迭代器。迭代器提供一個(gè)對(duì)象來順序訪問聚合對(duì)象中的一系列數(shù)據(jù),而不暴露聚合對(duì)象的內(nèi)部表示。迭代器模式的優(yōu)點(diǎn):
- 無須暴露聚合對(duì)象的內(nèi)部表示
- 遍歷任務(wù)交由迭代器完成,簡(jiǎn)化聚合類
- 遍歷的方式可擴(kuò)展
模式結(jié)構(gòu)
迭代器模式主要包含以下角色。
- 抽象聚合(Aggregate)角色:定義存儲(chǔ)、添加、刪除聚合對(duì)象以及創(chuàng)建迭代器對(duì)象的接口。
- 具體聚合(ConcreteAggregate)角色:實(shí)現(xiàn)抽象聚合類,返回一個(gè)具體迭代器的實(shí)例。
- 抽象迭代器(Iterator)角色:定義訪問和遍歷聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。
- 具體迭代器(Concretelterator)角色:實(shí)現(xiàn)抽象迭代器接口中所定義的方法,完成對(duì)聚合對(duì)象的遍歷,記錄遍歷的當(dāng)前位置。
源碼導(dǎo)讀
集合類的迭代器我們沒少用,我們來看看它的相關(guān)源碼吧,以 ArrayList 為例,它就是一個(gè)collection的具體聚合,其方法 iterator() 便是獲取迭代器的方法:
public Iterator<E> iterator() {
return new Itr();
}
z這個(gè) Itr 是它的內(nèi)部類:
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
// 部分源碼省略
}
它的私有內(nèi)部類實(shí)現(xiàn)了 Iterator 接口:
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
這就是一個(gè)迭代器的抽象接口。定義了對(duì)聚合對(duì)象的訪問方法。
這里說一下設(shè)計(jì)亮點(diǎn) Itr ,它是個(gè)私有的內(nèi)部類;這樣做的好處是做到了足夠的約束,避免使用者去以不合理的方式創(chuàng)建迭代器,并且可以自由的訪問外部類的私有屬性, 這樣的設(shè)計(jì)方式同樣適合建造者模式。
我們簡(jiǎn)單分析下 Itr 對(duì)外部類屬性的遍歷 它的三個(gè)屬性值標(biāo)記遍歷的相關(guān)信息。
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
我們看 Itr.next() 方法,Object[] elementData = ArrayList.this.elementData 就是獲取外部類對(duì)象的數(shù)據(jù),這個(gè)elementData 就是實(shí)際存儲(chǔ)我們數(shù)據(jù)的對(duì)象,所以說ArrayList的底層是數(shù)組;這里有個(gè)有意思的冷知識(shí) transient 關(guān)機(jī)鍵,在 ArrayList 中 它屬性是這樣定義的:
transient Object[] elementData
這個(gè)關(guān)鍵字修飾的屬性,在序列化對(duì)象的時(shí)候,這個(gè)屬性不會(huì)被序列化,這么做的原因感興趣的可以自行百度,這里不做太多分析。