1. 程式人生 > >設計模式的藝術 行為型模式之迭代器模式

設計模式的藝術 行為型模式之迭代器模式

前言

現在的電視機都配置了一個遙控器,使用者可以通過遙控器去選擇上一個或者下一個臺,我們只需要知道如何使用這個遙控器,而無須關注電視是怎麼把電視訊道放入其中的,在軟體實際的開發中,也有這麼一種類,它儲存著多個成員物件,這些類通常稱為聚合類,對應的物件稱為聚合物件。為了方便操作這些聚合物件,同時可以很靈活的為聚合物件增加不同的遍歷的方法,也需要類似電視機遙控器一樣的角色,可以訪問物件的同時又不暴露它內部的結構

什麼是迭代器模式 Iterator Pattern

提供一種方法來訪問聚合物件,而不用暴露這個物件的內部表示,其別名為遊標(Cursor),迭代器模式是一種物件行為型模式

迭代器模式的優點

(1)、支援以不同的方式遍歷一個聚合物件,在同一個聚合物件上可以定義多種遍歷方式。在迭代器模式中只需要用一個迭代器來替換原有的迭代器即可改變遍歷演算法,也可以自定義迭代器的子類以支援新的遍歷方式。

(2)、迭代器簡化了聚合類。由於引入了迭代器,在原有的聚合物件中不需要再自行提供資料遍歷等方法,這樣可以簡化聚合類的設計

(3)、在迭代器模式中,由於引入了抽象層,增加新的聚合類和迭代器都很方便,無須修改原有程式碼,滿足了開閉原則的要求

迭代器模式的缺點

(1)、由於迭代器模式將儲存資料和遍歷資料的職責分離,增加新的聚合類需要對應增加新的迭代器類,類的個數成對的增加,這在一定程度上增加了系統的複雜性

(2)、抽象迭代器的設計難度較大,需要充分考慮到系統將來的擴充套件,例如JDK中內建迭代器Iterator就無法實現逆向遍歷,如果需要實現逆向遍歷,只能通過其子類ListIerator等來實現,而ListIterator迭代器無法用於操作Set型別的聚合物件。在自定義迭代器時,建立一個考慮全面的抽象迭代器並不是一件很容易的事情

迭代器模式的適用場景

(1)、訪問一個聚合物件的內容而無須暴露它的內部表示。將聚合物件的訪問與內部資料的儲存相分離,使得訪問聚合物件時無須瞭解其內部實現細節

(2)、需要為一個聚合物件提供多種遍歷方式

(3)、為遍歷不同的聚合結構提供一個統一的介面,在該介面的實現類中為不同的聚合機構提供不同的遍歷方式,而客戶端可以統一的操作該介面

迭代器模式的具體實現

 

抽象聚合類

package com.company;

import java.util.ArrayList;
import java.util.List;

public abstract class AbstractObjectList {
    protected List<Object> objects=new ArrayList<Object>();

    public AbstractObjectList(List<Object> objects) {
        this.objects = objects;
    }
    public void removeObject(Object object){
        this.objects.remove(object);
    }
    public List getObjects(){
        return  this.objects;
    }
    //宣告建立迭代器物件的抽象方法
    public abstract AbstractIterator createIterator();
}

具體聚合類

package com.company;

import java.util.List;

//商品資料類:集體聚合類
public class ProductList extends AbstractObjectList {
    public ProductList(List<Object> objects) {
        super(objects);
    }

    @Override
    //實現建立迭代器物件的具體工廠類
    public AbstractIterator createIterator() {
        return new ProductIterator(this);
    }
}

抽象迭代器類

package com.company;

public interface AbstractIterator {
    public void next(); //移至下一個元素
    public boolean isLast(); //判斷是否為最後一個元素
    public void previous();  //移至上一個元素
    public boolean isFirst();  //判斷是否為第一個元素
    public Object getNextItem(); //獲取下一個元素
    public Object getPreviousItem(); //獲取上一個元素
}

具體產品迭代器類

package com.company;

import java.util.List;

//商品迭代器:具體迭代器
public class ProductIterator implements AbstractIterator {
    private ProductList productList;
    private List products;
    private int cursor1;  //定義一個遊標,用於記錄正向遍歷的位置
    private int cursor2;  //定義一個遊標,用於記錄逆向遍歷的位置

    public ProductIterator(ProductList productList) {
        this.productList = productList;
        this.products=productList.getObjects();
        cursor1=0;    //設定正向遍歷遊標的初始值
        cursor2=products.size()-1;  //設定逆向遊標的初始值
    }

    @Override
    public void next() {
            if(cursor1<products.size()){
                cursor1++;
            }
    }

    @Override
    public boolean isLast() {
        return (cursor1==products.size());
    }

    @Override
    public void previous() {
        if(cursor2>-1){
            cursor2--;
        }
    }

    @Override
    public boolean isFirst() {
        return (cursor2==-1);
    }

    @Override
    public Object getNextItem() {
        return products.get(cursor1);
    }

    @Override
    public Object getPreviousItem() {
        return products.get(cursor2);
    }
}

客戶端測試類

package com.company;

import java.util.ArrayList;
import java.util.List;

public class Client {

    public static void main(String[] args) {
        List products = new ArrayList();
        products.add("倚天劍");
        products.add("屠龍刀");
        products.add("斷腸草");
        products.add("葵花寶典");
        products.add("四十二章經");
        AbstractObjectList list;
        AbstractIterator iterator;
        list = new ProductList(products);  //建立聚合物件
        iterator = list.createIterator();  //建立迭代器物件
        System.out.println("正向遍歷");
        while (!iterator.isLast()) {
            System.out.println(iterator.getNextItem() + ",");
            iterator.next();
        }
        System.out.println();
        System.out.println("---------------------");
        System.out.println("逆向遍歷");
        while (!iterator.isFirst()) {
            System.out.println(iterator.getPreviousItem() + ",");
            iterator.previous();
        }
    }
}