設計模式——疊代器模式

架構師的修煉之路 發佈 2020-01-06T04:13:24+00:00

上一篇中介紹了一種行為型設計模式——策略模式,這篇文章中介紹另外一個比較簡單的行為型設計模式——疊代器模式。概念一提到疊代器模式很多人可能感覺很陌生,但是實際上,疊代器模式是所有設計模式中最簡單也是最常用的設計模式,正是因為他太常用了,所以很多人忽略了他的存在。

上一篇中介紹了一種行為型設計模式——策略模式,這篇文章中介紹另外一個比較簡單的行為型設計模式——疊代器模式。

概念

一提到疊代器模式很多人可能感覺很陌生,但是實際上,疊代器模式是所有設計模式中最簡單也是最常用的設計模式,正是因為他太常用了,所以很多人忽略了他的存在。

疊代器模式提供一種方法訪問一個容器中各個元素,而又不需要暴露該對象的內部細節。

那麼,這裡提到的容器是什麼呢?其實就是可以包含一組對象的數據結構,如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。

關鍵字: