JAVA設計模式之 迭代器模式【Iterator Pattern】

小呂-ICE發表於2014-12-01

一、概述

    提供一種方法來訪問聚合物件(容器container),而不用暴露這個物件的內部細節。屬於物件行為型模式。

二、適用場景

    1>遍歷訪問聚合物件中的元素,而無須暴露它的內容表示,將聚合物件的訪問和內部資料的儲存分離。使得訪問聚合物件時無須瞭解其內部的實現細節。

    2>需要為一個聚合物件提供多種遍歷實現。


三、UML類圖


四、參與者

 1>Iterator(抽象迭代器):它定義了訪問和遍歷元素的介面,宣告瞭用於遍歷資料元素的方法,例如:用於獲取第一個元素的first()方法,用於訪問下一個元素的next()方法,用於判斷是否還有下一個元素的hasNext()方法,用於獲取當前元素的currentItem()方法等,在具體迭代器中將實現這些方法。

 2>ConcreteIterator(具體迭代器):它實現了抽象迭代器介面,完成對聚合物件的遍歷,同時在具體迭代器中通過遊標來記錄在聚合物件中所處的當前位置,在具體實現時,遊標通常是一個表示位置的非負整數。

 3>Aggregate(抽象聚合類):它用於儲存和管理元素物件,宣告一個createIterator()方法用於建立一個迭代器物件,充當抽象迭代器工廠角色。

 4>ConcreteAggregate(具體聚合類):它實現了在抽象聚合類中宣告的createIterator()方法,該方法返回一個與該具體聚合類對應的具體迭代器ConcreteIterator例項。


五、用例學習

1、抽象迭代器 Iterator.java

/**
 * 自定義迭代器介面<br/>
 * <b>說明:</b>
 * 此處沒有使用JDK內建的迭代器介面 java.util.Iterator<E>
 * @author  lvzb.software@qq.com
 *
 */
public interface Iterator {
    /** 將遊標指向第一個元素  */
	public Object first();
	/** 將遊標指向下一個元素  */
	public Object next();
	/** 判斷是否存在下一個元素  */
	public boolean hasNext();
	/** 返回遊標指向的當前元素  */
	public Object currentItem();
}

2、具體迭代器 ConcreteIterator.java

/**
 * 具體迭代器實現類<br/>
 * 訪問聚合物件、對聚合物件內部元素遍歷
 * @author  lvzb.software@qq.com
 *
 */
public class ConcreteIterator implements Iterator {
	// 維持一個對具體聚合物件的引用,以便於訪問儲存在聚合物件中的資料  
	private Aggregate aggregate;
	// 定義一個遊標,用於記錄當前訪問位置  
	private int cursorIndex; 

	public ConcreteIterator(Aggregate aggregate){
		this.aggregate = aggregate;
	}
	
	@Override
	public Object first() {
		cursorIndex = 0;
        return aggregate.getObjects().get(cursorIndex);
	}

	@Override
	public Object next() {
		cursorIndex++ ;
		if(hasNext()){
			return aggregate.getObjects().get(cursorIndex);
		} 
		return aggregate.getObjects().get(0);
	}

	@Override
	public boolean hasNext() {
		if (cursorIndex < aggregate.getObjects().size()) {
			return true;
		}
		return false;
	}

	@Override
	public Object currentItem() {
		return aggregate.getObjects().get(cursorIndex);
	}

}
3、抽象聚合類 Aggregate.java

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

/**
 * 抽象聚合物件
 * @author  lvzb.software@qq.com
 *
 */
public abstract class Aggregate {
	
	/** 建立迭代器  具體建立什麼樣迭代方式的迭代器由具體的子類去實現 */
	public abstract Iterator createIterator();
	
    protected List<Object> objects = new ArrayList<Object>();  
	
	public Aggregate(List objects) {  
        this.objects = objects;  
    } 
	
	public void addObject(Object obj){
		objects.add(obj);
	}
	
	public void deleteObject(Object obj){
		objects.remove(obj);
	}
	
	public List<Object> getObjects(){
		return objects;
	}

}
4、具體聚合類 ConcreteAggregate.java

import java.util.List;

/**
 * 具體聚合物件
 * @author  lvzb.software@qq.com
 *
 */
public class ConcreteAggregate extends Aggregate {

	public ConcreteAggregate(List objects) {
		super(objects);
	}

	/**
	 * 提供工廠方法 建立具體的迭代器例項<br/>
	 * 由迭代器去執行具體的聚合物件的遍歷訪問<br/>
	 * 這樣就將聚合物件的資料儲存 和 對聚合物件元素的訪問進行了分離
	 */
	@Override
	public Iterator createIterator() {
		return new ConcreteIterator(this);
	}

}
5、客戶端測試類 Client.java

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

public class Client {

	public static void main(String[] args){
		List<String> nameList = new ArrayList<String>();
		nameList.add("Java");
		nameList.add("C");
		nameList.add("C++");
		
		// 例項化具體聚合物件 且 建立初始化集合資料
		ConcreteAggregate languageAggregate = new ConcreteAggregate(nameList);
		// 獲取聚合物件關聯的迭代器
		Iterator iterator = languageAggregate.createIterator();
		
		// 通過迭代器訪問聚合物件的內部資料
		String firstLanguage = (String) iterator.first();  // 訪問聚合物件集合中索引為1的元素 
		System.out.println(firstLanguage);
		
		boolean hasNext = iterator.hasNext();
		System.out.println("是否還有下一個元素:" + hasNext);
		
		if(hasNext){
			String nextLanguage = (String) iterator.next(); 
			System.out.println("下一個元素:" + nextLanguage);
		}
	}
	
}
6、執行效果

Java
是否還有下一個元素:true
下一個元素:C



六、其他/擴充套件

Java JDK內建的迭代器:

    說到迭代器模式 給我們的第一聯想就是Java中 我們使用最最頻繁的java.util.Iterator介面啦。

沒錯 他就是JDK中內建的迭代器。public interfaceIterator<E> 對collection進行迭代的迭代器。

 

    這裡想擴充套件的一個點是:關於介面Iterator的子介面ListIterator<E>的介紹

這個ListIterator子介面 也許我們平時的程式碼中使用的少,那麼他有什麼功能呢?

下面先看兩張截圖<比較比較 答案就在其中>

Iterator API方法:


ListIterator API方法:


從上面兩個截圖分析中我們可以看出Iterator只能進行單向遍歷,而ListIterator可以進行雙向遍歷(向前/向後),且可以在迭代期間修改列表。最後附上一張截圖如下:






相關文章