設計模式——叠代器(Iterator)模式
- 概述
叠代器模式簡單的說(按我目前的理解)就是一個類提供一個對外叠代的接口,方面調用者叠代。這個叠代接口至少包括兩個方法:hasNext()--用於判斷是否還有下一個,next()--用於取出下一個對象(或值)。而外部使用這個類(取出這個類中的對象或值)時,不用關心這個類存儲對象或數據的具體數據結構,即使這個類的存儲數據結構臨時發生改變,調用者不作任何代碼修改仍然可以正常工作。從而實現代碼的可重用性和低耦合性。下面以實例說明。
- 實例
假設有兩個書架(BookShelf),一個書架用數組Array的形式存放書,另一個書架用ArrayList的形式存放書,兩個書架可以存放多本書(Book)的名字,Main方法通過書架取出書名打印出來。
傳統模式:很容易想到第一個書架通過一個方法返回存放書的數組,另一個書架返回存放書的ArrayList。就像下面這樣:
//傳統模式: public Book[] getBooks(){ return books; }
//普通模式 public ArrayList<Book> getBooks(){ return books; }
這樣的缺點是什麽呢?缺點在於當我們同時獲取到這兩個書架時,叠代輸出的方式就有所不同,因為一個是數組,一個是List,這個很容易想到吧,可能你覺得很簡單,但是如果有十個,有幾十個用不同的數據結構存儲呢,叠代的方式又要改。並且,如果我開始用的數組存放書,後來我又不想用數組而改用List存放呢?那豈不是既要修改存放書的代碼的同時又要修改叠代輸出的代碼?Oh,No..太麻煩了吧。可能你會想自己寫的代碼,幹嘛每個書架存放書的數據結構要不同呢?那如果不是自己寫的呢?比如我現在要合並多個餐館的菜單為一個菜單並輸出打印,而這些菜單的存儲方式肯定不同,很有可能這幾個餐館的代碼都不是同一個人寫的。這時候我們再去一個一個循環未免也太麻煩。
使用叠代器模式:既然我不同的書架存放書的數據結構不同,那我可以每個書架對外提供一個叠代接口,而每個接口都包含有hasNext方法和Next方法。這時在外部循環叠代輸出時,就不用擔心每個書架的書是怎樣存放的,我只需要能通過Next方法取出書就可以了,就像下面這樣:
數組存放:
public class BookShelf { private Book[] books; private int last = 0; 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 last; } // //傳統模式: // public Book[] getBooks(){ // return books; // } public Iterator iterator() { // return new BookShelfIterator(this); return new BookShelfIterator(); } class BookShelfIterator implements Iterator{ // private BookShelf bookShelf; //采用內部類,可以直接調用外部類方法,不用添加引用。 private int index ; public BookShelfIterator() { // this.bookShelf=bookShelf; this.index = 0; } @Override public boolean hasNext() { if (index < getLength()){ return true; }else { return false; } } @Override public Object next() { Book book = getBookAt(index); index++; return book; } } }
ArrayList存放:
import java.util.ArrayList; public class BookShelf1 { private ArrayList<Book> books ;//使用ArrayList實現 public BookShelf1(int maxsize) { this.books = new ArrayList<>(maxsize);//初始大小 } public Book getBookAt(int index){ return books.get(index); } public void appendBook(Book book){ this.books.add(book); } public int getLength(){ return books.size(); } public Iterator iterator() { return new BookShelfIterator(); } // //普通模式 //// public ArrayList<Book> getBooks(){ //// return books; //// } class BookShelfIterator implements Iterator{ // private BookShelf bookShelf; //采用內部類,可以直接調用外部類方法,不用添加引用。 private int index ; public BookShelfIterator() { // this.bookShelf=bookShelf; this.index = 0; } @Override public boolean hasNext() { if (index < getLength()){ return true; }else { return false; } } @Override public Object next() { Book book = getBookAt(index); index++; return book; } } }
而我們獲取這兩個書架的書時,只需要調用兩個書架的iterator()方法就可以獲取到同樣的Iterator對象,這個對象中都包含兩個相同的方法hasNext()和Next(),這樣我們就很方便的叠代輸出了,並且我們不用關心每個書架裏面是通過數組還是list存放書的。就像下面這樣:
ArrayList<Iterator> iterList = new ArrayList<>(); //存放Iterator BookShelf bookShelf = new BookShelf(4);//實例化第一個書架 bookShelf.appendBook(new Book("Around the World in 80 Days")); bookShelf.appendBook(new Book("Bible")); bookShelf.appendBook(new Book("Daddy-Long-Legs")); bookShelf.appendBook(new Book("Cinderella")); Iterator it = bookShelf.iterator(); iterList.add(it); BookShelf1 bookShelf1 = new BookShelf1(4);//實例化第二個書架 bookShelf1.appendBook(new Book("Around the World in 80 Days__")); bookShelf1.appendBook(new Book("Bible__")); bookShelf1.appendBook(new Book("Daddy-Long-Legs__")); bookShelf1.appendBook(new Book("Cinderella__")); Iterator it1 = bookShelf1.iterator(); iterList.add(it1); for (int i = 0; i < iterList.size(); i++) { Iterator iterator = iterList.get(i); while (iterator.hasNext()){ Book book = (Book) iterator.next(); System.out.println(book.getName()); } }
- 完整代碼
請移步:https://github.com/yyc007/DesignPatterns/
- 小結
使用叠代器模式,可以幫助我們編寫可以復用的類,當這個類發生改變時,不需要對其它的類進行修改或者很小的修改即可應對。就上面的書架例子來說,不管BookShelf如何變化,只要BookShelf返回的Iterator類的實例沒有問題(hasNext方法和Next方法都可以正常工作),即使調用方不對叠代輸出的While循環做任何修改都可以正常工作。
設計模式——叠代器(Iterator)模式