設計模式之迭代器模式

王若伊_恩赐解脱發表於2024-08-31

迭代器模式(Iterator)用於在資料集合中按照順序遍歷集合,在遍歷的同時不需要暴露物件的內部表示,根據不同的需求我們可以採用不同的方式遍歷集合,它主要解決三個問題 1、能夠遍歷一個集合物件。2、我們不需要了解集合物件的內部結構。3、能夠提供多種不同的遍歷方式。

迭代器模式的適用場景

迭代器模式是與集合共生共死的,一般來說,我們只要實現一個集合,就需要同時提供這個集合的迭代器,就像java中的Collection,List、Set、Map等,這些集合都有自己的迭代器。假如我們要實現一個這樣的新的容器,當然也需要引入迭代器模式,給我們的容器實現一個迭代器。引自

接下來就通過示例程式進行迭代器的學習。

UML類圖

設計模式之迭代器模式
這裡寫圖片描述

這段程式的目的就是將書(Book)放到書架(BookShelf)中,並將書的名字按順序顯示出來。如果你對類圖不熟悉可移步 Java利器之UML類圖詳解

介面

Aggregate 介面是所需要遍歷集合的介面,有一個iterator方法,該方法返回一個用於遍歷集合的迭代器,即建立出按順序訪問儲存在我內部元素的物件。

public interface Aggregate {
    public abstract Iterator iterator();
}複製程式碼

當想要遍歷集合中元素時,可以呼叫iterator方法來生成一個實現了Iterator介面的類的例項。對於Iterator介面就是遍歷集合元素的,類似於for迴圈,在此該介面簡單實現為

public interface Iterator {
    public abstract boolean hasNext();
    public abstract Object next();
}複製程式碼

對於這兩個方法應該很常見,hasNext()返回布林型別表示是否有下一個元素,存在下一個元素就返回true,否則返回false,返回false時也就表示該集合元素已全部被遍歷,也是終止條件。next方法返回的就是集合中的當前指向元素,並且將迭代器指向下一個元素,而這些操作,都是Iterator的實現類中處理的。

Book類

public class Book {

    private String name;

    public Book(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}複製程式碼

BookShelf

該類就是表示書架的類,該類有一個陣列books用於存放書籍,並提供了獲取資料,新增書籍及書籍數量的方法,由於實現了Aggregate介面,則需重寫iterator方法,該方法返回BookShelfIterator類的例項作為該類的iterator。當外部想要遍歷書架時就呼叫這個方法。

public class BookShelf implements Aggregate {
    private Book[] books;
    private int last;
    public BookShelf(int maxsize) {
        this.books = new Book[maxsize];
    }
    public Book getBookAt(int index) {
        return books[index];
    }
    public void appendBook(Book book) {
        this.books[last] = book;
        last++;
    }
    public int getLength() {
        return books.length;
    }
    @Override
    public Iterator iterator() {
        return new BookShelfIterator(this);
    }
}複製程式碼

BookShelfIterator

該類是具體的迭代器,實現了Iterator 介面,是迭代器的具體實現,它包含了遍歷集合所必要的資訊,bookShelf表示要遍歷的書架,index表示當前迭代器所指向書籍的下標,構造方法接收要遍歷的書架,並將index初始化為0,hasNext方法是實現介面Iterator的方法,當index小於書架書的長度時表示有下一個資料,否則沒有返回false.next方法就是返回當前所指向的書籍,並將index加一指向下一本書,在這裡相當於for迴圈中i++.讓迴圈變數指向下一個元素。

public class BookShelfIterator implements Iterator {
    private int index;
    private BookShelf bookShelf;

    public BookShelfIterator(BookShelf bookShelf) {
        this.bookShelf = bookShelf;
        this.index = 0;
    }

    @Override
    public boolean hasNext() {
        if (index < bookShelf.getLength()) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Object next() {
        Book book=bookShelf.getBookAt(index);
        index++;
        return book;
    }

}複製程式碼

至此迭代器以及實現完畢了,接下來寫測試類進行書架裝書和遍歷。

public class Main {

    public static void main(String[] args) {
        BookShelf bookShelf=new BookShelf(4);
        bookShelf.appendBook(new Book("圖解設計模式"));
        bookShelf.appendBook(new Book("未來簡史"));
        bookShelf.appendBook(new Book("Android效能優化"));
        bookShelf.appendBook(new Book("程式設計師修煉之道"));
        Iterator iterator=bookShelf.iterator();
        while (iterator.hasNext()) {
            Book book = (Book) iterator.next();
            System.out.println(book.getName());
        }
    }

}複製程式碼

輸出資訊

圖解設計模式
未來簡史
Android效能優化
程式設計師修煉之道複製程式碼

優點

說了這麼多,也許你會疑問為什麼引入Iterator這種複雜的設計模式呢?如果是陣列,直接for迴圈遍歷就可以了。
當然引入迭代器模式最重要的理由是它可以將遍歷和實現分離開來,在示例程式中

        while (iterator.hasNext()) {
            Book book = (Book) iterator.next();
            System.out.println(book.getName());
        }複製程式碼

它只使用了Iterator的hasNext和next方法,並沒有呼叫BookShelf的方法,也就是說這裡的迴圈並不依賴於BookShelf的實現。如果BookShelf開發者想放棄陣列,用Vector取而代之,會如何?不管如何變化只要它能生成Iterator例項,即使不對while迴圈做修改,依然能保證程式正常執行。

在示例程式中,只是簡單的實現從前到後遍歷,當然也可以是其他方式,如從後向前,以及跳躍式遍歷。

好了,關於迭代器模式到這裡已經介紹完畢了。有問題歡迎留言指出,Have a wonderful day .

如需文章中所寫程式碼,請移步GitHub檢視

相關文章