迭代器模式 | Iterator Pattern

Posted by Ian Tsai on Thursday, October 1, 2020

本系列文章同步分享於IT邦幫忙第12屆鐵人賽


Design Pattern 系列文章導讀


Design Pattern可以說是開發上大家都會遇到的一個課題, 這系列文會從Design Principles、各種design pattern到最後的Anti-Patterns & Code Smells介紹下去,讓我們可以更了解各種pattern的使用時機與場合。 預計目標主題如下,若有哪部分不熟的章節可以直接點進去看
註:可以利用Online Java Compiler IDE

  1. 設計模式 - 入門篇
  2. 設計模式 - 原則篇 | Design Principles
  3. 設計模式 - 創建型模型篇 | Creational Patterns
  4. 設計模式 - 結構型模型篇 | Structural Patterns
  5. 設計模式 - 行為型模型篇 | Behavioural Patterns
  6. 設計模式 - 番外篇
  • 定義


提供一種方法可以順序性讀取一個集合物件中的各個元素,而又不會暴露該物件的內部表示。

迭代器模式將集合對象的遍歷行為分離出來,讓抽象迭代器類別來實作。他的目的在於不暴露集合內部物件的內部結構,讓外部可以呼叫集合的內部數據。如 Java 中的 Collection、List、Set、Map 等都包含了迭代器。

  • Iterator Pattern 成員


成員 功用
Aggregate 定義新增、儲存、刪除集合物件及建立迭代器物件的接口。
ConcreteAggregate 實作Aggregate,回傳一個迭代器的實體。
Iterator 定義呼叫及遍歷集合元素的接口,通常包含hasNext()、first()、next() 等方法。
Concretelterator 實現Iterator所定義的方法,完成集合物件的遍歷及記錄當前的位置。
  • Iterator Pattern 實作


以前國中考高中時,會選填志願,我們拿這個例子來實作。

首先先建立抽象集合,並定義方法。

//抽象集合
interface Aggregate { 
    public void add(Object obj);  // 新增元素
    public void remove(Object obj);  // 移除元素
    public Iterator getIterator();  // 取得集合
}

定義完介面後,接著要建立ConcreteAggregate實作Aggregate。

//實體集合
class ConcreteAggregate implements Aggregate { 
    private List<Object> list = new ArrayList<Object>();  // 存放元素的集合
    public void add(Object obj) { 
        list.add(obj); 
    }
    public void remove(Object obj) { 
        list.remove(obj); 
    }
    public Iterator getIterator() {
        return(new ConcreteIterator(list)); 
    }     
}

這樣就將集合物件做好了。

再來就是迭代器的部分,我們選填完志願後,想要看第一個、下一個、上一個、最後一個志願以及是否還有下一間學校的功能,所以Iterator必須要先定義好。

//抽象迭代器
interface Iterator {
    Object first();
    Object next();
    Object previous();
    Object last();
    boolean hasNext();
}

接著ConcreteIterator實作Iterator。

//實體迭代器
class ConcreteIterator implements Iterator { 
    private List<Object> list=null; 
    private int index=-1; 
    public ConcreteIterator(List<Object> list) { 
        this.list=list; 
    } 
    public boolean hasNext() { 
        if(index<list.size()-1) { 
            return true;
        }
        else {
            return false;
        }
    }
    public Object first() {
        index=0;
        Object obj=list.get(index);;
        return obj;
    }
    public Object next() {
        Object obj=null; 
        if(this.hasNext()) { 
            obj=list.get(++index); 
        } 
        return obj; 
    }   
    public Object previous() {
        Object obj=null; 
        if(this.hasNext()) { 
            obj=list.get(--index); 
        } 
        return obj; 
    }  
    public Object last() {
        index=list.size()-1;
        Object obj = list.get(index);
        return obj;
    }
}

最後我們就可以使用看看。

public class Main {
    public static void main(String[] args) {
        Aggregate ag = new ConcreteAggregate(); 
        ag.add("建國中學"); 
        ag.add("師大附中"); 
        ag.add("成功高中");
        ag.add("松山高中");
        ag.add("中崙高中");
        ag.add("麗山高中");
        System.out.print("學校列表:");
        Iterator it = ag.getIterator(); 
        while(it.hasNext()) { 
            Object ob=it.next(); 
            System.out.print(ob.toString()+"\t"); 
        }
        Object ob=it.first();
        System.out.println("\nFirst:"+ob.toString());
        
        Scanner scanner = new Scanner(System.in);
        
        boolean end = false;

        while (!end){
            System.out.println("請輸入選項(1:第一所;2:下一所;3:最後一所):");
            int num = scanner.nextInt();
            if (num == 1){
                System.out.println("顯示的學校為:" +  it.first().toString());
            } else if (num == 2){
                if (it.hasNext()){
                    System.out.println("顯示的學校為:" +  it.next().toString());
                } else {
                    System.out.println("已經到最後一筆");
                }
            } else if (num == 3){
                System.out.println("顯示的學校為:" +  it.last().toString());
            } else {
                System.out.println("請輸入正確指令" );
            }
        }
    }
}

  • 小結


Iterator Pattern的目標

提供一種方法可以順序性讀取一個集合物件中的各個元素,而又不會暴露該物件的內部表示。

Iterator Pattern的成員
Aggregate:定義新增、儲存、刪除集合物件及建立迭代器物件的接口。
ConcreteAggregate:實作Aggregate,回傳一個迭代器的實體。
Iterator:定義呼叫及遍歷集合元素的接口,通常包含hasNext()、first()、next() 等方法。
Concretelterator:實現Iterator所定義的方法,完成集合物件的遍歷及記錄當前的位置。
Iterator Pattern的優缺點
優點
1. 呼叫一個物件內容不需要知道他的內部。
2. 遍歷任務交由迭代器完成,簡化了集合類別。
3. 擴展性好,不需修改原本程式碼。
4. 封裝性好,為不同的集合結構提供統一的接口。
缺點
由於增加類別個數,在一定程度上增加了系統的複雜性。
Iterator Pattern的使用時機
1. 需要集合物件提供多種遍歷方法。
2. 需要遍歷不同的集合結構而提供統一的接口時。
  • 範例程式碼


範例:Iterator Pattern 實作

  • References


  • 迭代器模式(详解版)
  • 迭代器模式
  • 反覆器模式 (Iterator Pattern)