23天設計模式之迭代器模式
文章簡介
今天在看Vector類的原始碼時發現集合基本上都使用到了迭代器模式,去了解了迭代器模式的相關知識,於是就有了這篇文章!在文章中我會拿我們最熟悉的ArrayList類來舉例,對應迭代器中的幾種角色一一闡釋清楚。廢話不多說,文章獻上。
是什麼
迭代器模式(Iterator),提供一種方法順序訪問一個聚合物件中的各種元素,而又不暴露該物件的內部表示。簡單來說就是提供了對集合等聚合結構的遍歷所有元素的方法。
物件的內部表示指的是什麼?這個我暫時也不清楚。不過我理解的大體意思是指,使用者不用關心這個集合中元素是怎麼排列的,使用者只需要通過這個介面就能依次拿到所有元素。
作用
- 訪問一個聚合物件的內容而無需暴露它的內部表示
- 支援對聚合物件的多種遍歷
- 為遍歷不同的聚合結構提供一個統一的介面
當然,上述幾個概念都是從百度百科看來的,都比較容易理解,我也就不再一一囉嗦了。
角色
- Iterator(迭代器介面):迭代器定義訪問和遍歷元素的介面。
- ConcreteIterator (具體迭代器):實現迭代器介面,真正地實現迭代元素。
- Aggregate (聚合介面):建立相應迭代器物件的介面,比如
List<E>
介面。 - ConcreteAggregate (具體聚合):實現聚合介面,並提供一個方法返回一個具體迭代器。比如
ArrayList<E>
。
角色之間的關係圖示:(配色可還行?)
下面來找找ArrayList類中對應的上述幾個角色。
圖示如下:(idea中可以顯示diagram圖,可以去鼓搗鼓搗?)
這樣一來就很清楚角色之間的關係了。
接下來我們再看看ArrayList的原始碼中,上述角色的體現。
// 寫一個測試類呼叫iterator()方法
public class Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
// 按住Ctrl+左鍵點選iterator()檢視它的實現
Iterator<String> iterator = list.iterator();
}
}
// 發現list.iterator();呼叫的是ArrayList的iterator()方法
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
public Iterator<E> iterator() {
// 該方法直接構造了一個Itr物件,說明Itr也是一個迭代器,再往下看Itr類
return new Itr();
}
// Itr類是一個ArrayList的內部類,並且實現了迭代器介面,也就是一個具體的迭代器物件,就是上述的 ConcreteIterator
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;
Itr() {}
// 再回到上面看ArrayList,它實現了List介面,List介面又繼承了Collection<E>介面
public interface List<E> extends Collection<E> {
// List介面也有iterator()方法,說明ArrayList的iterator()方法就是實現List後的來的
Iterator<E> iterator();
// 再看Collection介面,繼承了Iterable介面
public interface Collection<E> extends Iterable<E> {
Iterator<E> iterator();
// Iterable介面就是頂層介面了,它提供了3個方法,常用的是前兩個方法
public interface Iterable<T> {
// 因此,Collection下的所有集合的迭代器都是重寫此方法獲得的
Iterator<T> iterator();
// Collection下的所有集合都能使用foreach方法也是從這裡來的
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
自定義實現倒序輸出的迭代器
接下來,我們通過自己定義四種角色來完成倒序輸出的迭代器模式。(實戰一波?)
- 定義抽象介面,包含返回迭代器的方法
public interface MyIterable<T> {
MyIterator<T> iterator();
}
- 定義抽象迭代器
public interface MyIterator<E> {
boolean hasNext();
E next();
}
- 定義聚合介面
public interface MyList<E> extends MyIterable<E> {
@Override
MyIterator<E> iterator();
int size();
boolean add(E e);
}
- 實現聚合介面,並定義具體迭代器內部類
// 這個類是參考Vector類寫的, 只寫了add方法和size方法
public class MyInvertedList<E> implements MyList<E> {
protected Object[] elementData;
protected int initialCapacity;
protected int increment;
protected int elementCount;
public MyInvertedList(int initialCapacity, int increment) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
if (increment < 0)
throw new IllegalArgumentException("Illegal increment: "+
increment);
this.initialCapacity = initialCapacity;
this.increment = increment;
this.elementData = new Object[initialCapacity];
}
// size是元素的個數而不是陣列的長度
@Override
public int size() {
return elementCount;
}
@Override
public boolean add(E e) {
if (elementData.length == elementCount) {
// 新增時超出陣列長度時自動擴容
elementData = Arrays.copyOf(elementData, elementData.length + increment);
}
elementData[elementCount++] = e;
return true;
}
@Override
public MyIterator<E> iterator() {
return new InvertedIterator();
}
// 使用內部類的好處是可以直接拿到this物件
private class InvertedIterator implements MyIterator<E> {
// 因為我們要倒敘輸出,所以index是從後往前,而不是從0往後
int index = elementCount;
@Override
public boolean hasNext() {
return index > 0;
}
@Override
public E next() {
index--;
return (E) elementData[index];
}
}
}
- 測試,使用迭代器倒序輸出元素
public class Test {
public static void main(String[] args) {
MyList<String> list = new MyInvertedList<>(5, 1);
list.add("111");
list.add("111");
list.add("222");
list.add("333");
list.add("444");
System.out.println("擴容前 size:" + list.size());
list.add("555");
list.add("666");
System.out.println("擴容後 size:" + list.size());
MyIterator<String> iterator = list.iterator();
// 倒序輸出
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
// 輸出
擴容前 size:5
擴容後 size:7
666
555
444
333
222
111
111
小結
可以說,迭代器模式是最常用的設計模式了,在元素遍歷的地方基本上都能使用到迭代器模式。
完結撒花!!!???
以上
感謝您花時間閱讀我的部落格,以上就是我對迭代器模式的一些理解,若有不對之處,還望指正,期待與您交流。
本篇博文系原創,僅用於個人學習,轉載請註明出處。???