前言
這次要介紹的是迭代器模式,也是一種行為模式。我現在覺得寫部落格有點應付了,前陣子一天一篇,感覺這樣其實有點沒理解透徹就寫下來了,而且寫完後自己也沒有多看幾遍,上次在面試的時候被問到java中的I/O的各種實現用到了什麼設計模式,我愣是想半天沒想出來了,人家還給提示了我也沒想出來,最後還是面試官給出的答案,是裝飾模式,聽到答案後就恍然大悟了,前兩天剛看了裝飾模式,還寫下了I/O操作中的各種類都是用到了裝飾模式,後來想想兩方面原因造成的當時沒回答出來,一是面試時緊張就容易想不起來,二是對設計模式理解的還是不夠透徹。所以以後寧可寫部落格慢一些也要將自己寫的東西理解透徹了。
迭代器模式概念介紹
迭代器模式,又稱遊標模式。這種模式提供一種方法訪問一個容器物件中各個元素,而又不需要暴露該對象的內部細節。這種模式其實我們日常開發中也很常見,例如下面的情境:
java.util.Iterator<String> it = list.iterator(); while (it.hasNext()){ //using "it.next();" do some business logic }
這樣來理解簡單一些,下面還是通過具體的情境例子來實現迭代器模式。
舉例
一個書架上放著好幾本書,現在我想知道書架上都有哪些書,並且都把書名列印出來。那麼書架就可以具有迭代的功能,能把它存放的所有書籍都迭代出來。用代碼實現如下:
定義一個迭代器介面,包含檢測是否還有下一個元素的方法和獲得下一個元素的方法
/** * 迭代器介面 */public interface Iterator { /** * 檢測是否還有下一個元素 * @return */ public abstract boolean hasNext(); /** * 獲得下一個元素 * @return */ public abstract Object next();}
定義含有迭代器對象的介面
/** * 只有實現此介面的才可以獲得迭代器對象 */public interface Aggregate { /** * 獲得迭代器對象 * @return */ public abstract Iterator iterator();}
書籍類
/** * 書籍類 */public class Book { //書籍名稱 private String name = ""; public Book(String name){ this.name = name; } /** * 獲得書籍名稱 * @return */ public String getName(){ return name; }}
書架類
/** * 書架類 */public class BookShelf implements Aggregate{ private Book[] books; private int last = 0; public BookShelf(int maxSize){ this.books = new Book[maxSize]; } /** * 獲得書籍 * @param index * @return */ public Book getBookAt(int index){ return books[index]; } /** * 添加書籍 * @param book */ public void appendBook(Book book){ this.books[last] = book; last++; } /** * 獲得書架上的書籍數量 * @return */ public int getLength(){ return books.length; } /** * 獲得書架迭代器對象 * @return */ @Override public Iterator iterator(){ return new BookShelfIterator(this); }}
書架迭代器
/** * 書架迭代器 */public class BookShelfIterator implements Iterator { private BookShelf bookShelf; private int index; public BookShelfIterator(BookShelf bookShelf){ this.bookShelf = bookShelf; this.index = 0; } /** * 檢測是否還有下一本書 * @return */ @Override public boolean hasNext() { if(index<bookShelf.getLength()){ return true; }else { return false; } } /** * 返回下一本書 * @return */ @Override public Object next() { Book book = bookShelf.getBookAt(index); index++; return book; }}
測試類別
public class Client { public static void main(String[] args) { //建立一個書架 BookShelf bookShelf = new BookShelf(5); //向書架中添加書籍 bookShelf.appendBook(new Book("深入理解Java虛擬機器")); bookShelf.appendBook(new Book("Java編程思想")); bookShelf.appendBook(new Book("高效能MySQL")); bookShelf.appendBook(new Book("Effective Java 中文版")); bookShelf.appendBook(new Book("資料結構與演算法分析Java語言描述")); //獲得書架迭代器 Iterator iterator = bookShelf.iterator(); //迭代 while (iterator.hasNext()){ Book book = (Book) iterator.next(); System.out.println(book.getName()); } }}
運行結果
深入理解Java虛擬機器Java編程思想高效能MySQLEffective Java 中文版資料結構與演算法分析Java語言描述
上面的這個例子就是實現了迭代器模式,可以看出來是在用戶端和容器間加入了迭代器,這樣就很好的避免容器內部細節的暴露,而且也使得設計符合“單一職責原則”。
迭代器模式的結構
迭代器模式主要由以下角色群組成
抽象迭代器角色(Iterator):抽象迭代器角色定義訪問和遍曆元素的介面。上面例子中的Iterator介面就是代表的這個角色。
具體迭代器角色(Concrete Iterator):具體迭代器角色要實現迭代器介面, 並要記錄遍曆中的當前位置。上面例子中BookShelfIterator類就是代表的這個角色。
容器角色(Aggregate):容器角色負責提供建立具體迭代器角色的介面。上面的例子中的Aggregate介面代表的就是這個角色。
具體容器角色(Concrete Aggregate):具體容器角色實現建立具體迭代器角色的介面,這個具體迭代器角色與該容器的結構相關。上面例子中書架類BookShelf
代表的就是這個角色。
總結
迭代器模式是一種使用頻率非常高的設計模式,通過引入迭代器可以將資料的遍曆功能從彙總對象中分離出來,彙總對象只負責儲存資料,而遍曆資料由迭代器實現完成。Java語言類庫中已經實現了迭代器模式,在實際開發中我們直接使用已經定義好的迭代器就可以了,像List、Set等集合都可以直接使用。
優點
1、它支援以不同的方式遍曆一個彙總對象,在同一個彙總對象上可以定義多種遍曆方式。替換迭代器就可以切換遍曆方法。
2、迭代器簡化了彙總類。彙總對象可以不用自己再提供遍曆方法。
3、在迭代器模式中由於引入了抽象層,增加新的彙總類和迭代器類都很方便,無須修改原有代碼,滿足“開閉原則”的要求。
缺點
1、由於迭代器模式將儲存資料和遍曆資料的職責分離,增加新的彙總類需要對應增加新的迭代器來,類的個數成對增加,這在一定程度上增加了系統的複雜性。
2、抽象迭代器設計難度相對較大,需要充分考慮到系統將來的擴充,,例如JDK內建迭代器Iterator就無法實現逆向遍曆,如果需要實現逆向遍曆,只能通過其子類ListIterator等來實現,而ListIterator迭代器無法用於操作Set類型的彙總對象。
適用情境
在以下情況可以考慮使用迭代器模式
1、訪問一個彙總對象的內容而無須暴露它的內部表示。將彙總對象的訪問與內部資料的儲存分離,使得訪問彙總對象時無須瞭解其內部實現細節。
2、需要為一個彙總對象提供多種遍曆方式。
3、為遍曆不同彙總結構提供統一的介面,該介面的實作類別中為不同的彙總結構提供不同的遍曆方式,而用戶端可以一致性的操作該介面。
想瞭解更多的設計模式請查看Java設計模式學習記錄-GoF設計模式概述。