天天看點

Java的設計模式(九):疊代器模式,Java源碼中的疊代器模式運用

作者:Code404

疊代器模式(Iterator Design Pattern)是一種行為型模式,它提供了一種通路容器對象中各個元素的方法,而且不需要了解容器對象内部實作結構。

疊代器模式分離了聚集對象的周遊行為,抽象出疊代器類負責具體疊代過程,進而可以使得聚集對象更容易的被複用。

在本篇文章中,我将詳細闡述疊代器模式的原理、使用場景以及示例,希望能夠幫助讀者更好的了解和掌握該模式。

一、疊代器模式原理

疊代器模式主要由以下幾個角色組成:

1、疊代器(Iterator):定義通路和周遊元素的接口,具體疊代器負責實作這些接口。

2、具體疊代器(Concrete Iterator):具體實作疊代器接口中的方法,完成對聚集對象的周遊。

3、聚集對象(Aggregate):定義建立疊代器的接口,即工廠方法,具體聚集對象傳回相應的具體疊代器執行個體。

4、具體聚集對象(Concrete Aggregate):實作聚集對象接口,傳回一個具體疊代器執行個體。

我們可以通過一個簡單的示例來更好的了解疊代器模式。

假設我們要實作一個簡單的數列,包括添加元素、删除元素和周遊元素等功能。這時我們可以使用疊代器模式來達到這個目的。

首先,我們定義一個疊代器接口:

public interface Iterator {
    boolean hasNext(); // 是否還有下一個元素
    Object next(); // 傳回下一個元素
}           

然後,我們定義一個聚集對象接口:

public interface Aggregate {
    void add(Object obj); // 添加元素
    void remove(Object obj); // 删除元素
    Iterator createIterator(); // 建立疊代器
}           

接下來,我們實作具體疊代器類:

public class ConcreteIterator implements Iterator {
    private List<Object> list; // 數列
    private int index = 0; // 目前元素下标
    
    public ConcreteIterator(List<Object> list) {
        this.list = list;
    }
    
    @Override
    public boolean hasNext() {
        if (index < list.size()) {
            return true;
        }
        return false;
    }
    
    @Override
    public Object next() {
        Object obj = null;
        if (hasNext()) {
            obj = list.get(index++);
        }
        return obj;
    }
}           

最後,我們實作具體聚集對象類(代碼如下):

public class ConcreteAggregate implements Aggregate {
    private List<Object> list = new ArrayList<>();
    
    @Override
    public void add(Object obj) {
        list.add(obj);
    }
    
    @Override
    public void remove(Object obj) {
        list.remove(obj);
    }
    
    @Override
    public Iterator createIterator() {
        return new ConcreteIterator(list);
    }
}           

現在,我們就可以使用疊代器模式來實作數列的周遊功能了,示例代碼如下:

public class IteratorPatternDemo {
    public static void main(String[] args) {
        Aggregate aggregate = new ConcreteAggregate();
        aggregate.add("元素A");
        aggregate.add("元素B");
        aggregate.add("元素C");
        aggregate.add("元素D");
        
        Iterator iterator = aggregate.createIterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}           

執行上述代碼後,我們就可以看到數列中所有的元素被周遊輸出了。

二、Java源碼中的疊代器模式

在我們使用非常頻繁的 Java 集合中,就使用了疊代器模式。下面以常用的 ArrayList 集合部分源碼講解 Java 實作疊代器模式的方式。

首先,在 Java 源碼的 java.util.Iterator 類中定義了疊代器的基本接口方法,hasNext、next、remove。源碼如下:

public interface Iterator<E> {

    boolean hasNext();

    E next();

    default void remove() {
        throw new UnsupportedOperationException("remove");
    }

   .....
}           

然後,在 ArrayList 中,定義了一個内部類 Itr 實作了 Iterator 接口。源碼如下:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    ......

    public Iterator<E> iterator() {
        // 傳回一個疊代器對象
        return new Itr();
    }

    /**
     * An optimized version of AbstractList.Itr
     */
    private class Itr implements Iterator<E> {
        int cursor;       // 下一個待傳回元素的位置
        int lastRet = -1; // 最後一次傳回元素的位置; 如果沒有則為-1
        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]; // 傳回下一個元素
        }

        public void remove() {
            // 删除目前疊代器傳回的元素
            if (lastRet < 0)
                throw new IllegalStateException(); // 抛出異常,表示沒有上一個元素
            checkForComodification(); // 檢查集合是否被修改過

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount; // 修改集合結構次數
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException(); // 抛出異常,表示集合的結構被修改
            }
        }

        ......
    }

    ......

}           

從上面代碼可以看到,使用 iterator() 方法可以擷取到一個疊代器對象,使用這個疊代器對象就可以變量集合裡的元素。

值得一提的是,remove() 方法中的下面這一行代碼

expectedModCount = modCount; // 修改集合結構次數           

這一行代碼的作用,使在用疊代器周遊集合的同時,又對集合元素進行删除操作,不會在周遊下一個元素時抛出 ConcurrentModificationException 異常。這裡又是一個面試經常會問到的問題。

三、總結

通過本篇文章的講解,我們可以看出疊代器模式的優點,它将聚集對象中各個元素的周遊行為進行了分離,進而使得聚集對象更容易被複用。同時,該模式也十分符合Java的設計原則,即“面向接口程式設計”,這樣一來,我們可以為同一個聚集對象定義不同的疊代器,以滿足不同的需求。

當然,疊代器模式也有一些缺點,例如其可擴充性不太好,疊代器隻能依次通路聚集對象中的各個元素,在某些情況下,這可能會導緻效率低下。此外,對于一些簡單的聚集對象,使用疊代器模式也可能會增加代碼的複雜性。

總的來說,疊代器模式在Java中的應用是非常廣泛的,它可以幫助我們更好的管理和周遊聚集對象中的各個元素,提高代碼的可讀性和可維護性,同時也充分展現了Java語言的面向對象特性和設計原則。

對于本文中的内容,不知道你有沒有什麼看法,歡迎在評論區裡留言。如果你對我的文章内容感興趣,歡迎點選關注,謝謝支援![謝謝][謝謝][謝謝]

文章連結:【Java程式員必須掌握的15個設計模式,特點和使用場景彙總整理!】

繼續閱讀