迭代器模式
定義:提供一種方法,順序訪問一個集合對象中的各個元素,而又不暴露該對象的內部表示
類型:行爲型
適用場景:
- 訪問一個集合對象的內容而無需暴露它的內部表示
- 爲遍歷不同的集合結構提供一個統一的接口
優點:
- 分離了集合對象的遍歷行爲
- 封裝性良好,用戶只需要得到迭代器就可以遍歷,而對於遍歷算法則不用去關心
缺點:
- 類的個數成對增加
UML類圖:
抽象容器角色(Aggregate):負責提供創建具體迭代器角色的接口,一般是一個接口,提供一個iterator()方法,例如java中的Collection接口,List接口,Set接口等。
具體容器角色(ConcreteAggregate):就是實現抽象容器的具體實現類,比如List接口的有序列表實現ArrayList,List接口的鏈表實現LinkedList,Set接口的哈希列表的實現HashSet等。
抽象迭代器角色(Iterator):負責定義訪問和遍歷元素的接口。
具體迭代器角色(ConcreteIterator):實現迭代器接口,並要記錄遍歷中的當前位置。
示例
舉一個簡單的例子,有一個書櫃,書櫃上放有一堆的書籍,我們在可以對這個書櫃存放書籍或移除書籍,也可以查看所有書籍的信息,這裏的目的是遍歷獲取到所有的書籍信息
- 書籍類
/**
* 書籍
*/
public class Book {
/**
* 書籍名稱
*/
private String name;
/**
* 書籍價格
*/
private double price;
public Book(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
- 書籍集合接口
/**
* 書籍集合接口
*/
public interface BookAggregate {
/**
* 添加書籍
* @param book
*/
void addCourse(Book book);
/**
* 移除書籍
* @param book
*/
void removeCourse(Book book);
/**
* 獲取書籍迭代器
* @return
*/
Iterator getBookIterator();
}
- 書籍集合實現類
/**
* 書籍集合實現類
*/
public class BookAggregateImpl implements BookAggregate{
private List<Book> bookList = new ArrayList<>();
@Override
public void addCourse(Book book) {
bookList.add(book);
}
@Override
public void removeCourse(Book book) {
bookList.remove(book);
}
@Override
public Iterator getBookIterator() {
return new BookIterator(bookList);
}
}
- 迭代器接口
/**
* 迭代器接口
*/
public interface Iterator {
/**
* 獲取下一個書籍元素
* @return
*/
Book nextBook();
/**
* 是否是最後一個
* @return
*/
boolean isLast();
}
- 具體書籍迭代器
package com.yaolong.demo.designpattern.behaviour.iterator;
import java.util.List;
/**
* 具體書籍迭代器
*/
public class BookIterator implements Iterator {
private List<Book> bookList;
private int position;
private Book book;
public BookIterator(List bookList) {
this.bookList = bookList;
}
@Override
public Book nextBook() {
System.out.println("返回書籍,位置是" + position);
book = bookList.get(position);
position++ ;
return book;
}
@Override
public boolean isLast() {
if(position < bookList.size()){
return false;
}
return true;
}
}
- 客戶端
/**
* 迭代器模式
*/
public class Client {
public static void main(String[] args) {
Book book1 = new Book("辟邪劍譜", 20);
Book book2 = new Book("葵花寶典", 32);
Book book3 = new Book("九陽神功", 40);
Book book4 = new Book("九陰真經", 50);
BookAggregate bookAggregate = new BookAggregateImpl();
bookAggregate.addCourse(book1);
bookAggregate.addCourse(book2);
bookAggregate.addCourse(book3);
bookAggregate.addCourse(book4);
Iterator bookIterator = bookAggregate.getBookIterator();
while(!bookIterator.isLast()){
System.out.println(bookIterator.nextBook());
}
//移除後
System.out.println("");
System.out.println("移除一本書後:");
bookIterator = bookAggregate.getBookIterator();
bookAggregate.removeCourse(book1);
while(!bookIterator.isLast()){
System.out.println(bookIterator.nextBook());
}
}
}
返回書籍,位置是0
Book{name=’辟邪劍譜’, price=20.0}
返回書籍,位置是1
Book{name=’葵花寶典’, price=32.0}
返回書籍,位置是2
Book{name=’九陽神功’, price=40.0}
返回書籍,位置是3
Book{name=’九陰真經’, price=50.0}移除一本書後:
返回書籍,位置是0
Book{name=’葵花寶典’, price=32.0}
返回書籍,位置是1
Book{name=’九陽神功’, price=40.0}
返回書籍,位置是2
Book{name=’九陰真經’, price=50.0}
以上的例子就是我們自定義了一個迭代器接口並實現了迭代器的功能,BookAggregate實例將集合的位置判斷、遍歷行爲委託給了Iterator實例,而不需要向客戶端暴露自己內部的集合結構。通常爲了方便維護,這個迭代器實現我們以一個內部類的進行提供。實際上,我們一般很少自己去定義迭代器接口,如jdk中提供了java.lang.Iterable(相當於BookAggregate)和java.util.Iterator(相當於我們上面定義的Iterator)都是現成的接口,如果我們自己定義的數據結構需要實現遍歷輸出,實現這兩個接口即可
相關的設計模式
- 迭代器模式和訪問者模式
都是迭代地訪問集合中的各個元素,訪問者模式中擴展開放的部分是作用於對象的操作上,而在迭代器模式中,擴展開放的部分是在集合對象的種類上,二者的實現方式上有很大的區別
使用典範
- java.util.ArrayList