設計模式:迭代器模式
一、前言
設計模式有很多,最典型的是GoF的23種設計模式,聽起來很多,其實大部分我們都是見過的,按照常見度來分,最常用的差不多是六七個吧,因此,我們在學習的時候應該有輕重緩急之分,不能一視同仁,而應該抓住重點,將一些最常用的設計模式吃透了,那么我們在遇到一個實際問題的時候就能根據問題的需要來進行相應的取舍。學習是一個循環往復的過程,沒有學過一次不再接觸就能掌握的,一定要反復的記憶,反復的練習,不斷地提煉,不斷地提高,沒有復習的學習就是參觀,沒有預習的學習就是做夢,沒有提升的學習就是浪費時間。
二、迭代器模式
什么叫做迭代器,我們可能在C++的STL標准模板庫或者在Java中見過iterator這個東西,所謂“迭代”就是按照一定的次序或順序進行重復操作,這個操作可以是遍歷也可以是反復的計算,而迭代器就是按照一定的順序對元素進行遍歷的過程。理解到這個程度,我們可能非常的奇怪,因為我們完全可以使用一個for循環來完成這樣的操作,又何必大費周章的來一個迭代器來遍歷呢?!這就涉及到軟件設計中最重要的一個原則了,那就是高內聚,低耦合。當我們使用for循環來完成遍歷操作的時候代碼中有着大量的耦合,當我們需要修改代碼的時候,不能做到少改甚至不改遍歷的代碼,而迭代器可以做到,這為代碼的可移植性、可擴展性等特性奠定了基礎。我們可以看到設計模式大多數是把簡單的問題給搞復雜了,但是這種復雜恰恰是為了以后設計和擴展的簡單。正如沒有規划的蓋一座房子,很快就蓋成了一座房子,可是因為沒有考慮到房子的方位、地基、以后的擴展、居住的舒適,改出來的房子最后不能進行擴展並且不符合力學的美感和力感,最終只能重新拆掉重建,所以學習設計模式的時候最好看一些建築方面的設計,明白全局觀的重要性。
廢話少說,直接上代碼(talk is cheap,let's show code!)
Book 類的定義:
1 package zyr.dp.iterator; 2 3 public class Book { 4 private String name; 5 6 public Book(String name) { 7 this.name = name; 8 } 9 10 public String getName() { 11 return name; 12 } 13 }
Aggregate 接口的定義:
1 package zyr.dp.iterator; 2 3 public interface Aggregate { 4 public abstract Iterator iterator(); 5 }
BookShelf 類的定義:
1 package zyr.dp.iterator; 2 3 public class BookShelf implements Aggregate { 4 private Book[] books; 5 int pointer=0; 6 public BookShelf(int max_size){ 7 books=new Book[max_size]; 8 } 9 public void appendBook(Book book){ 10 books[pointer]=book; 11 pointer++; 12 } 13 public Book findBookAt(int index){ 14 return books[index]; 15 } 16 public int getLength(){ 17 return pointer; 18 } 19 public Iterator iterator(){ 20 return new BookShelfIterator(this); 21 } 22 }
Iterator 接口的定義:
1 package zyr.dp.iterator; 2 3 public interface Iterator { 4 public abstract boolean hasNext(); 5 public abstract Object next(); 6 }
BookShelfIterator 類的定義:
1 package zyr.dp.iterator; 2 3 public class BookShelfIterator implements Iterator { 4 5 BookShelf bookShelf; 6 int index; 7 public BookShelfIterator(BookShelf bookShelf){ 8 this.bookShelf=bookShelf; 9 index=0; 10 } 11 public boolean hasNext() { 12 if(index<this.bookShelf.getLength()){ 13 return true; 14 } 15 return false; 16 } 17 18 public Object next() { 19 return bookShelf.findBookAt(index++); 20 } 21 }
Main 函數:
1 package zyr.dp.iterator; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 7 Book book1 = new Book("朝花夕拾"); 8 Book book2 = new Book("圍城"); 9 Book book3 = new Book("遮天"); 10 Book book4 = new Book("尋秦記"); 11 Book book5 = new Book("駱駝祥子"); 12 13 BookShelf bookShelf = new BookShelf(5); 14 15 bookShelf.appendBook(book1); 16 bookShelf.appendBook(book2); 17 bookShelf.appendBook(book3); 18 bookShelf.appendBook(book4); 19 bookShelf.appendBook(book5); 20 21 Iterator it= bookShelf.iterator(); 22 while(it.hasNext()){ 23 Book book=(Book)it.next(); 24 System.out.println("書的名字為《"+book.getName()+"》"); 25 } 26 } 27 }
運行結果:
三、分析
在上面我們的程序中,有着很多值得說明的地方,首先是類、接口的結構,我們可以使用下面的圖來表達,從圖中我們可以看出,最核心的是兩個對象,一個是書架這樣的一個書的集合books[],代表了需要遍歷的元素;另一個就是迭代器,好像一個工具,用到的時候將this對象代指的書架集合放里面,進行遍歷,不需要的時候束之高閣。同時為什么會有接口呢,其實接口的作用是為了降低耦合度,在main函數中,我們使用的是Iterator這個接口來定義的引用,而不是BookShelfIterator,這樣做的好處是完全屏蔽了內部的細節,在用戶使用的時候,完全不知道BookShelfIterator的存在。
引入迭代器之后,可以將元素的遍歷和實現分離開來,如下面的代碼中的while循環,沒有依賴與BookShelf的實現,沒有使用BookShelf的其他方法,只是用了迭代器中hasNext和next方法。可復用指的是將一個類作為一個組件,當一個組件改變時,不需要對其他組件進行修改或者只進行少量的修改就可以實現修改后的功能。同樣的Iterator it= bookShelf.iterator();面向接口編程,便於程序的修改和維護。
1 Iterator it= bookShelf.iterator(); 2 while(it.hasNext()){ 3 Book book=(Book)it.next(); 4 System.out.println("書的名字為《"+book.getName()+"》"); 5 }
同樣的,迭代器的種類非常多,我們可以根據遍歷的次序進行設計,來實現相應的功能。從該設計模式中我們可以看到接口的應用,面向接口編程的概念,以及元素的遍歷與實現分離,實現了高內聚和低耦合。