Java設計模式筆記之迭代器模式

1.迭代器模式

迭代器(子)模式(Iterator)又叫遊標模式,是對象的行爲模式。迭代器模式可以順序的訪問一個聚集中的元素,而不用暴露聚集的內部表象

2.爲什麼需要迭代器模式

一個聚集持有多個對象,就需要對客戶端提供遍歷對象的方法,使用過程可能會出現以下問題:

(1)迭代邏輯沒有改變,但是需要將一種聚集換成另一種聚集。

(2)聚集沒有改變,但是迭代方式需要改變,例如新增可以刪除元素的功能。

出現這些問題,就需要修改客戶端代碼或者修改聚集的方法。這是因爲聚集對象和迭代邏輯耦合過緊,需要新增迭代子對象,將迭代邏輯封裝到裏面,從而與聚集本身分開

不同的聚集可以提供相同的迭代器對象,從而使客戶端無需知道知道聚集的底層結構。

一個聚集可以提供多個不同的迭代對象,從而使得遍歷邏輯的變化不會影響到聚集本身

3.迭代器模式結構

迭代器模式的一般結構圖如下:


  • Iterator:抽象迭代器,定義遍歷元素所需的所有接口
  • ConcreteIterator:具體迭代器,實現Iterator的所有接口,並保持迭代過程中的遊標位置。
  • Aggregate:聚集角色,提供聚集接口和創建迭代器的接口。
  • ConcreteAggregate:具體聚集角色,持有元素對象,並實現創建具體迭代器對象的接口。
  • Client:客戶端,持有聚集及其迭代器對象的引用,使用迭代器對象訪問或者操作聚集中的元素。

4.迭代器的兩種實現方式

(1)白箱聚集和外稟迭代子

聚集對外界透明,提供訪問自己元素的接口,迭代子只保持一個迭代的遊標位置,並通過聚集的接口訪問其中的元素。
示例代碼:
Aggregate.java(抽象聚集)
package com.patterns.iterator.whitebox;

abstract public class Aggregate
{
    public Iterator createIterator()
    {
        return null;
    }
}

ConcreteAggregate.java(具體聚集)
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;
    }
}

Iterator.java(抽象迭代器)
public interface Iterator
{
    void first();

    void next();

    boolean isDone();

    Object currentItem();
}

ConcreteIterator.java(具體迭代器)
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)黑箱聚集與內稟迭代器

黑箱聚集不向外部提供遍歷自己元素對象的接口,爲了是迭代器訪問聚集的元素,需要把迭代器實現成聚集的內部類(內稟迭代器)。
這種迭代器的實現和(1)白箱聚集和外稟迭代子  的實現不同在於聚集的實現和具體迭代器的實現,其他代碼與(1)中一樣

ConcreteAggregate.java
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.迭代器模式的優缺點

(1)優點
  1. 將迭代過程封裝到迭代器中,簡化了聚集代碼,並且簡化了客戶端的遍歷代碼。
  2. 每個聚集可以有幾個不同的迭代器,互不影響。
  3. 封裝性良好,客戶端不必知道聚集的遍歷算法,只要得到迭代器就可以使用
(2)缺點
  1. 迭代器容易讓人產生聚集都是線性結構的錯覺,有可能會得到意料之外的結果
  2. 對於簡單聚集,例如ArrayList,迭代器比較繁瑣。






發佈了71 篇原創文章 · 獲贊 2 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章