簡述-迭代器模式
阿新 • • 發佈:2018-11-25
介紹
一個容器,必然會涉及到遍歷演算法,如果將它封裝在容器中,則增加了複雜度,如果客戶實現,則不那麼方便。所以引入第三方類來幫忙處理,這個類就是迭代器。
又稱為遊標模式,行為型設計模式之一。我的理解是目的在遍歷,弱化容器與遍歷演算法的關係。在容器與訪問類中新增一個迭代器,用於承擔遍歷,又不需要訪問類自行實現。提供一種順序訪問一個容器物件中的各個元素,而又不需要暴露改物件的內部表示。
Android中資料庫cusor則使用到了該模式。各個語言一般都有各自的迭代器實現,開發中很少會自己去實現迭代器了。
UML
組成結構
- Iterator:迭代器介面,負責定義、訪問、遍歷元素的介面
- ConcreteIterator:具體迭代器類,實現迭代器介面,並記錄當前位置。
- Aggregate:容器介面,負責提供建立迭代器角色的介面
- ConcreteAggregate:具體容器類,具體迭代器角色與該容易相關聯
使用場景
- 遍歷一個容器物件時
事例
比如有兩個北鼻,他們喜歡的水果不同,咱們想遍歷問問她們喜歡的水果,先看看不用迭代器的方式:
- 建立一個水果物件,用於承載。簡易北鼻1和北鼻2物件,她們其中都有自己喜歡的水果列表持有,一個是以陣列方式,一個是以列表方式,並提供獲取陣列和列表的方法:
/** * 水果 */ public class ITeFruit { /** * 水果名稱 */ private String name; public ITeFruit(String name) { this.name = name; } @Override public String toString() { return "ITeFruit{" + "name='" + name + '\'' + '}'; } } /** * 北鼻1水果 */ public class Beibi1Fruit { private List<ITeFruit> iTeFruits = new ArrayList<>(); public Beibi1Fruit() { iTeFruits.add(new ITeFruit("菠蘿")); iTeFruits.add(new ITeFruit("香蕉")); iTeFruits.add(new ITeFruit("哈密瓜")); iTeFruits.add(new ITeFruit("榴蓮")); iTeFruits.add(new ITeFruit("火龍果")); } public List<ITeFruit> getiTeFruits(){ return iTeFruits; } } /** * 北鼻二喜歡的水果 */ public class Beibi2Fruit { private ITeFruit[] beibi2 = new ITeFruit[4]; public Beibi2Fruit() { beibi2[0] = new ITeFruit("蘋果"); beibi2[1] = new ITeFruit("梨子"); beibi2[2] = new ITeFruit("芒果"); beibi2[3] = new ITeFruit("哈密瓜"); } /** * 獲取北鼻二喜歡的水果陣列 * * @return 水果陣列 */ public ITeFruit[] getBeibi2Fruits() { return this.beibi2; } }
- 進行遍歷查詢(這個沒用增強for迴圈,那樣看就沒區別了):
//北鼻1,遍歷 Beibi1Fruit beibi1Fruit = new Beibi1Fruit(); List<ITeFruit> iTeFruits = beibi1Fruit.getiTeFruits(); System.out.println("北鼻一喜歡水果:"); for (int i = 0; i < iTeFruits.size(); i++) { System.out.println(iTeFruits.get(i)); } //北鼻2,遍歷 Beibi2Fruit beibi2Fruit = new Beibi2Fruit(); ITeFruit[] beibi2Fruits = beibi2Fruit.getBeibi2Fruits(); System.out.println("北鼻二喜歡水果:"); for (int i = 0; i < beibi2Fruits.length; i++) { System.out.println(beibi2Fruits[i]); }
輸出就不貼了,從這裡就能看到,遍歷兩個的水果,使用的方式是不一樣的,那麼對外界來說得知道每個的遍歷方式,相對麻煩了,那麼就引入了,提供一個迭代器來實現。
- 建立一個迭代器介面,提供獲取下一物件和是否還有下一個的方法:
/**
* 迭代器介面
*/
public interface IteratorF {
/**
* 是否還有下一個
*
* @return
*/
boolean hasNext();
/**
* 下一個
*
* @return 有則返回下一個物件,否則返回null
*/
Object next();
}
- 建立北鼻1和北鼻2的迭代器,其中各自實現迭代方法:
/**
* 北鼻1的迭代器
*/
public class Beibi1Iterator implements IteratorF {
private List<ITeFruit> iTeFruits = new ArrayList<>();
private int position;
public Beibi1Iterator(List<ITeFruit> iTeFruits) {
this.iTeFruits = iTeFruits;
}
@Override
public boolean hasNext() {
//如果列表中有個數且當前position還沒到末尾
return (iTeFruits.size() > 0 && position <= iTeFruits.size() - 1);
}
@Override
public Object next() {
//獲取一個水果,然後將position+1
return iTeFruits.get(position++);
}
}
/**
* 北鼻2的迭代器
*/
public class Beibi2Iterator implements IteratorF {
private ITeFruit[] beibi2 = new ITeFruit[4];
private int position;
public Beibi2Iterator(ITeFruit[] beibi2) {
this.beibi2 = beibi2;
}
@Override
public boolean hasNext() {
//如果陣列中有個數且當前position還沒到末尾
return (beibi2.length > 0 && position <= beibi2.length - 1);
}
@Override
public Object next() {
//獲取一個水果,然後將position+1
return beibi2[position++];
}
}
- 建立容器介面,提供一個獲取迭代器的方法(這裡簡單點,就只提供下獲取迭代器):
/**
* 容器介面,該介面返回一個迭代器,由容器來實現
*/
public interface Aggregate {
/**
* 返回一個迭代器
*
* @return 迭代器
*/
IteratorF iterator();
}
- 容器實現迭代器方法:
/**
* 北鼻1水果
*/
public class Beibi1Fruit implements Aggregate {
private List<ITeFruit> iTeFruits = new ArrayList<>();
public Beibi1Fruit() {
iTeFruits.add(new ITeFruit("菠蘿"));
iTeFruits.add(new ITeFruit("香蕉"));
iTeFruits.add(new ITeFruit("哈密瓜"));
iTeFruits.add(new ITeFruit("榴蓮"));
iTeFruits.add(new ITeFruit("火龍果"));
}
/**
* 建立一個迭代器並返回
*
* @return
*/
@Override
public IteratorF iterator() {
return new Beibi1Iterator(this.iTeFruits);
}
}
/**
* 北鼻二喜歡的水果
*/
public class Beibi2Fruit implements Aggregate {
private ITeFruit[] beibi2 = new ITeFruit[4];
public Beibi2Fruit() {
beibi2[0] = new ITeFruit("蘋果");
beibi2[1] = new ITeFruit("梨子");
beibi2[2] = new ITeFruit("芒果");
beibi2[3] = new ITeFruit("哈密瓜");
}
@Override
public IteratorF iterator() {
return new Beibi2Iterator(this.beibi2);
}
}
- 遍歷:
//北鼻1,遍歷
Beibi1Fruit beibi1Fruit = new Beibi1Fruit();
IteratorF iterator1 = beibi1Fruit.iterator();
System.out.println("北鼻一喜歡水果:");
while (iterator1.hasNext()) {
System.out.println(iterator1.next());
}
//北鼻2,遍歷
Beibi2Fruit beibi2Fruit = new Beibi2Fruit();
IteratorF iterator2 = beibi2Fruit.iterator();
System.out.println("北鼻二喜歡水果:");
while (iterator2.hasNext()) {
System.out.println(iterator2.next());
}
輸出和第一步是一樣的,但是看到遍歷的地方了嗎?這樣子遍歷就完全一樣了,對使用方來說就非常方便了。
優缺點
優點
- 自身優點單一,非常滿足單一職責原則。
缺點
- 對類檔案的增加
總結:這個設計模式雖然平時我們一般比較少主動去使用,是因為庫中已經有了,但是它遍歷的設計思想,提供給客戶的方便,內部的單一職責原則,是非常值得借鑑的。