1.迭代器模式
迭代器(子)模式(Iterator)又叫遊標模式,是對象的行爲模式。迭代器模式可以順序的訪問一個聚集中的元素,而不用暴露聚集的內部表象。
2.爲什麼需要迭代器模式
一個聚集持有多個對象,就需要對客戶端提供遍歷對象的方法,使用過程可能會出現以下問題:
(1)迭代邏輯沒有改變,但是需要將一種聚集換成另一種聚集。
(2)聚集沒有改變,但是迭代方式需要改變,例如新增可以刪除元素的功能。
出現這些問題,就需要修改客戶端代碼或者修改聚集的方法。這是因爲聚集對象和迭代邏輯耦合過緊,需要新增迭代子對象,將迭代邏輯封裝到裏面,從而與聚集本身分開。
不同的聚集可以提供相同的迭代器對象,從而使客戶端無需知道知道聚集的底層結構。
一個聚集可以提供多個不同的迭代對象,從而使得遍歷邏輯的變化不會影響到聚集本身。
3.迭代器模式結構
迭代器模式的一般結構圖如下:
- Iterator:抽象迭代器,定義遍歷元素所需的所有接口
- ConcreteIterator:具體迭代器,實現Iterator的所有接口,並保持迭代過程中的遊標位置。
- Aggregate:聚集角色,提供聚集接口和創建迭代器的接口。
- ConcreteAggregate:具體聚集角色,持有元素對象,並實現創建具體迭代器對象的接口。
- Client:客戶端,持有聚集及其迭代器對象的引用,使用迭代器對象訪問或者操作聚集中的元素。
4.迭代器的兩種實現方式
(1)白箱聚集和外稟迭代子
package com.patterns.iterator.whitebox;
abstract public class Aggregate
{
public Iterator createIterator()
{
return null;
}
}
package com.patterns.iterator.whitebox;
public class ConcreteAggregate extends Aggregate
{
/**
* 爲簡單起見,初始化一個數組
*/
private Object objs[]= {"Monk Tang",
"Monkey", "Pigsy",
"Sandy", "Horse"};
/**
* 實現創建迭代器的方法
*/
public Iterator createIterator()
{
return new ConcreteIterator(this);
}
/**
* 對外透明訪問持有元素的方法,迭代子通過次方法遍歷
* @param index
* @return
*/
public Object getElement(int index)
{
if (index < objs.length)
{
return objs[index];
}
else
{
return null;
}
}
public int size()
{
return objs.length;
}
}
public interface Iterator
{
void first();
void next();
boolean isDone();
Object currentItem();
}
public class ConcreteIterator implements Iterator
{
private ConcreteAggregate agg;
//迭代遊標
private int index = 0;
private int size = 0;
public ConcreteIterator(ConcreteAggregate agg)
{
this.agg = agg;
size = agg.size();
index = 0 ;
}
public void first()
{
index = 0 ;
}
public void next()
{
if (index < size)
{
index++;
}
}
public boolean isDone()
{
return (index >= size);
}
public Object currentItem()
{
return agg.getElement(index);
}
}
Client.java(客戶端)
public class Client
{
//迭代器對象
private Iterator it;
//聚集對象
private Aggregate agg = new ConcreteAggregate();
public void operation()
{
it = agg.createIterator();
while( !it.isDone() )
{
System.out.println(it.currentItem().toString());
it.next();
}
}
public static void main(String[] args)
{
Client client = new Client();
client.operation();
}
}
聚集提供了遍歷放,但是迭代器將迭代過程抽象化,使得客戶端和迭代邏輯分開。在聚集發生變化時,避免修改客戶端;在迭代方法發生變化時,避免修改聚集本身。
(2)黑箱聚集與內稟迭代器
package com.patterns.iterator.blackbox;
/**
* 不向外提供訪問內部元素的方法
* @author chenxh
*
*/
public class ConcreteAggregate extends Aggregate
{
/**
* 內部元素
*/
private Object[] objs = {"Monk Tang",
"Monkey", "Pigsy",
"Sandy", "Horse"};
/**
* 創建迭代器
*/
public Iterator createIterator()
{
return new ConcreteIterator();
}
/**
* 聚集內部類實現的迭代器,可以訪問外部類的私有屬性和方法
* @author chenxh
*
*/
private class ConcreteIterator
implements Iterator
{
//遊標
private int currentIndex = 0;
public void first()
{
currentIndex = 0;
}
public void next()
{
if ( currentIndex < objs.length )
{
currentIndex++;
}
}
public boolean isDone()
{
return (currentIndex == objs.length);
}
public Object currentItem()
{
return objs[currentIndex];
}
}
}
5.迭代器模式的優缺點
- 將迭代過程封裝到迭代器中,簡化了聚集代碼,並且簡化了客戶端的遍歷代碼。
- 每個聚集可以有幾個不同的迭代器,互不影響。
- 封裝性良好,客戶端不必知道聚集的遍歷算法,只要得到迭代器就可以使用
- 迭代器容易讓人產生聚集都是線性結構的錯覺,有可能會得到意料之外的結果
- 對於簡單聚集,例如ArrayList,迭代器比較繁瑣。