1. 程式人生 > >17、行為型-迭代器模式(Iterator)

17、行為型-迭代器模式(Iterator)

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

迭代器模式包含如下幾個角色:

● Iterator(抽象迭代器):它定義了訪問和遍歷元素的介面,聲明瞭用於遍歷資料元素的方法,例如:用於獲取第一個元素的first()方法,用於訪問下一個元素的next()方法,用於判斷是否還有下一個元素的hasNext()方法,用於獲取當前元素的currentItem()方法等,在具體迭代器中將實現這些方法。
● ConcreteIterator(具體迭代器):它實現了抽象迭代器介面,完成對聚合物件的遍歷,同時在具體迭代器中通過遊標來記錄在聚合物件中所處的當前位置,在具體實現時,遊標通常是一個表示位置的非負整數。
● Aggregate(抽象聚合類):它用於儲存和管理元素物件,宣告一個createIterator()方法用於建立一個迭代器物件,充當抽象迭代器工廠角色。
● ConcreteAggregate(具體聚合類):它實現了在抽象聚合類中宣告的createIterator()方法,該方法返回一個與該具體聚合類對應的具體迭代器ConcreteIterator例項

1、主要優點

(1) 它支援以不同的方式遍歷一個聚合物件,在同一個聚合物件上可以定義多種遍歷方式。在迭代器模式中只需要用一個不同的迭代器來替換原有迭代器即可改變遍歷演算法,我們也可以自己定義迭代器的子類以支援新的遍歷方式。
(2) 迭代器簡化了聚合類。由於引入了迭代器,在原有的聚合物件中不需要再自行提供資料遍歷等方法,這樣可以簡化聚合類的設計。
(3) 在迭代器模式中,由於引入了抽象層,增加新的聚合類和迭代器類都很方便,無須修改原有程式碼,滿足“開閉原則”的要求

2、主要缺點

(1) 由於迭代器模式將儲存資料和遍歷資料的職責分離,增加新的聚合類需要對應增加新的迭代器類,類的個數成對增加,這在一定程度上增加了系統的複雜性。
(2) 抽象迭代器的設計難度較大,需要充分考慮到系統將來的擴充套件,例如JDK內建迭代器Iterator就無法實現逆向遍歷,如果需要實現逆向遍歷,只能通過其子類ListIterator等來實現,而ListIterator迭代器無法用於操作Set型別的聚合物件。在自定義迭代器時,建立一個考慮全面的抽象迭代器並不是件很容易的事情。

3、適用場景

(1) 訪問一個聚合物件的內容而無須暴露它的內部表示。將聚合物件的訪問與內部資料的儲存分離,使得訪問聚合物件時無須瞭解其內部實現細節。
(2) 需要為一個聚合物件提供多種遍歷方式。
(3) 為遍歷不同的聚合結構提供一個統一的介面,在該介面的實現類中為不同的聚合結構提供不同的遍歷方式,而客戶端可以一致性地操作該介面

王者榮耀中的迭代器模式(英雄瀏覽):

輸入圖片說明

/**
 * 2018/12/6
 * 抽象聚合類
 *
 * @author machuanpeng
 */
public abstract class AbstractObjectList {
    
	protected List<Object> objects = new ArrayList<Object>();
 
	public AbstractObjectList(List objects) {
		this.objects = objects;
	}
	
	public void addObject(Object obj) {
		this.objects.add(obj);
	}
	
	public void removeObject(Object obj) {
		this.objects.remove(obj);
	}
	
	public List getObjects() {
		return this.objects;
	}
	
    //宣告建立迭代器物件的抽象工廠方法
	public abstract AbstractIterator createIterator();
}
/**
 * 2018/12/6
 * 英雄列表聚合類
 *
 * @author machuanpeng
 */
public class HeroList extends AbstractObjectList {
	public HeroList(List products) {
		super(products);
	}
	
    /**實現建立迭代器物件的具體工廠方法*/
	public AbstractIterator createIterator() {
		return new HeroIterator(this);
	}
}
/**
 * 2018/12/6
 * 抽象迭代器
 *
 * @author machuanpeng
 */
interface AbstractIterator {
	public void next(); //移至下一個元素
	public boolean isLast(); //判斷是否為最後一個元素
	public void previous(); //移至上一個元素
	public boolean isFirst(); //判斷是否為第一個元素
	public Object getNextItem(); //獲取下一個元素
	public Object getPreviousItem(); //獲取上一個元素
}
public class HeroIterator implements AbstractIterator {
	private HeroList heroList;
	private List heros;
	private int cursor1; //定義一個遊標,用於記錄正向遍歷的位置
	private int cursor2; //定義一個遊標,用於記錄逆向遍歷的位置
	
	public HeroIterator(HeroList list) {
		this.heroList = list;
		this.heros = list.getObjects(); //獲取集合物件
		cursor1 = 0; //設定正向遍歷遊標的初始值
		cursor2 = heros.size() -1; //設定逆向遍歷遊標的初始值
	}
	
	public void next() {
		if(cursor1 < heros.size()) {
			cursor1++;
		}
	}
	
	public boolean isLast() {
		return (cursor1 == heros.size());
	}
	
	public void previous() {
		if (cursor2 > -1) {
			cursor2--;
		}
	}
	
	public boolean isFirst() {
		return (cursor2 == -1);
	}
	
	public Object getNextItem() {
		return heros.get(cursor1);
	} 
		
	public Object getPreviousItem() {
		return heros.get(cursor2);
	} 	
}

測試:

public class Client {
	public static void main(String args[]) {
		List heros = new ArrayList();
		heros.add("百里守約");
		heros.add("牛魔");
		heros.add("典韋");
		heros.add("甄姬");
		heros.add("達摩");
			
		AbstractObjectList list;
		AbstractIterator iterator;
		
		list = new HeroList(heros); //建立聚合物件
		iterator = list.createIterator();	//建立迭代器物件
		
		System.out.println("正向遍歷:");	
		while(!iterator.isLast()) {
			System.out.print(iterator.getNextItem() + ",");
			iterator.next();
		}
		System.out.println("-----------------------------");
		System.out.println("逆向遍歷:");
		while(!iterator.isFirst()) {
			System.out.print(iterator.getPreviousItem() + ",");
			iterator.previous()