上一篇中介紹了一種行為型設計模式——策略模式,這篇文章中介紹另外一個比較簡單的行為型設計模式——疊代器模式。
概念
一提到疊代器模式很多人可能感覺很陌生,但是實際上,疊代器模式是所有設計模式中最簡單也是最常用的設計模式,正是因為他太常用了,所以很多人忽略了他的存在。
疊代器模式提供一種方法訪問一個容器中各個元素,而又不需要暴露該對象的內部細節。
那麼,這裡提到的容器是什麼呢?其實就是可以包含一組對象的數據結構,如Java中的Collection和Set。
用途
從疊代器模式的概念中我們也看的出來,疊代器模式的重要用途就是幫助我們遍歷容器。拿List來舉例。如果我們想要遍歷他的話,通常有以下幾種方式:
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i) + ",");
}
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + ",");
}
for (Integer i : list) {
System.out.print(i + ",");
}
其實,第二種和第三種都是基於疊代器模式實現的。本文重點是介紹疊代器模式,那麼先暫不介紹Java中內置的疊代器,我們嘗試自己實現一下疊代器模式,這樣更有助於我們徹底理解疊代器模式。
實現方式
疊代器模式包含如下角色:
Iterator 抽象疊代器
ConcreteIterator 具體疊代器
Aggregate 抽象容器
Concrete Aggregate 具體容器
這裡我們舉一個菜單的例子,我們有一個菜單,我們想要展示出菜單中所有菜品的名字和報價信息等。
先定義抽象疊代器:
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
}
這裡的疊代器提供了三個方法,分別包括hasNext方法、next方法和remove方法。
hasNext 返回該疊代器中是否還有未遍歷過的元素
next 返回疊代器中的下一個元素
在定義一個具體的疊代器:
public class MenuIterator implements Iterator {
String[] foods;
int position = 0;
public MenuIterator(String[] foods){
this.foods = foods;
}
@Override
public boolean hasNext() {
return position != foods.length;
}
@Override
public Object next() {
String food = foods[position];
position += 1;
return food;
}
}
這個具體的類實現了Iterator接口,並實現了其中的方法。具體實現就不詳細寫了,相信都能看得懂(請忽略線程安全問題)。
接下來定義一個抽象容器:
public interface Menu {
void add(String name);
Iterator getIterator();
}
這裡定義一個菜單接口,只提供兩個方法,一個add方法和一個getIterator方法,用於返回一個疊代器。
然後定義一個具體的容器,用於實現Menu接口:
public class ChineseFoodMenu implements Menu {
private String[] foods = new String[4];
private int position = 0;
@Override
public void add(String name) {
foods[position] = name;
position += 1;
}
@Override
public Iterator getIterator() {
return new MenuIterator(this.foods);
}
}
該類的實現也相對簡單。至此,我們已經具備了一個疊代器模式需要的所有角色。接下來寫一個測試類看看具體使用:
public class Main {
public static void main(String[] args) {
ChineseFoodMenu chineseFoodMenu = new ChineseFoodMenu();
chineseFoodMenu.add("宮保雞丁");
chineseFoodMenu.add("孜然羊肉");
chineseFoodMenu.add("水煮魚");
chineseFoodMenu.add("北京烤鴨");
Iterator iterator = chineseFoodMenu.getIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
//output:
//宮保雞丁
//孜然羊肉
//水煮魚
//北京烤鴨
我們通過疊代器的方式實現了對一個容器(Menu)的遍歷。疊代器的好處就是我們在Main類中使用Menu的時候根本不知道他底層的實現,只需要通過疊代器來遍歷就可以了。
總結
疊代器的使用現在非常廣泛,因為Java中提供了java.util.Iterator。而且Java中的很多容器(Collection、Set)也都提供了對疊代器的支持。
疊代器甚至可以從23種設計模式中移除,因為他已經普遍的可以稱之為工具了。
最後最後,疊代器模式很好用,本文中介紹了如何寫疊代器模式,但是,如果你要做Java開發,請直接用Java提供的Iterator。