Hello,大家好:
今天我們來聊一下設計模式中迭代器模式,
背景:
甲、乙、丙三人合作開發一套人員管理系統,甲在編程中習慣使用陣列存盤元素,乙喜歡編程中習慣使用List等集合存盤元素,丙在專案開發中剛好需要遍歷甲、乙存盤的元素,無奈,丙只能寫兩套不同的遍歷方法,上述場景用代碼描述為:
StudentContainer studentContainer = new StudentContainer();
List<Student> students = studentContainer.getStudents();
for (int i = 0; i < students.size(); i++) {
System.out.println(students.get(i).getStudentNum());
}
TeacherContainer teacherContainer = new TeacherContainer();
Teacher[] teachers = teacherContainer.getTeachers();
for (int i = 0; i < teachers.length; i++) {
System.out.println(teachers[i]);
}
注意,可能小伙伴們會說可以使用增強for回圈呀,其實那也是JDK對迭代器模式的一種實作,在后續的博客中我們將從JDK位元組碼層面來看看增強for回圈的原理,上述方式除了遍歷方式不一致外,丙還得知道甲乙兩人的內部存盤細節,然后他們討論,為了統一遍歷方式,以及不暴露自身內部存盤細節,對資料存盤進行了改進,
好了,經過討論,通用存盤模式類圖如下:

方法描述:addElement和removeElement方法用以增加和洗掉元素,next()、previous()、isFirst()等方法用以遍歷元素,
那么上述方法存在什么問題呢?
1、該類既要負責資料存盤,又要負責遍歷資料,違反設計模式單一職責原則,
2、如果將該類宣告為一個介面,交給子類去實作,那么這個介面必定包含大量方法,不利于子類去實作,違反介面隔離原則,
3、如果將遍歷交給子類負責,子類就肯定要訪問AbstractStoreElement中存盤的元素,就必須暴露AbstractStoreElement的內部存盤細節,不然子類無法進行遍歷,又破壞了AbstractStoreElement的封裝性,
于是甲乙丙三人將遍歷元素的方法提取出來,將資料存盤和資料遍歷分離開來,無須暴露AbstractStoreElement的內部存盤細節即可完成對它的遍歷,這就是迭代器模式的意圖所在,
最后經過改進得到的類圖如下:

AbstractStoreElement(抽象存盤類):用于存盤和管理元素物件的抽象類,具體如何管理交由子類去實作,宣告createIterator方法來創建一個迭代器,
ConcreteStorefElement(具體存盤類):繼承AbstractStoreElement,實作createIterator()方法,回傳一個與該具體存盤類對應的具體迭代器,
Iterator(抽象迭代器):定義訪問和遍歷元素的介面,宣告用于遍歷的方法,
ConcreteIterator(具體迭代器):它實作了抽象迭代器中的所有方法,完成對存盤類中的元素的遍歷操作,具體迭代器中通過游標來記錄在聚合物件中所處的當前位置,
附錄完整代碼:
AbstractStoreElement:
public abstract class AbstractStoreElement {
// 宣告創建迭代器物件的抽象工廠方法
public abstract AbstractIterator createIterator();
}
ConcreteStoreElement:
public class ConcreteStoreElement extends AbstractStoreElement {
protected List<Student> students = new ArrayList<Student>();
public ConcreteStoreElement(List<Student> students) {
this.students = students;
}
public void addObject(Student obj) {
this.students.add(obj);
}
public void removeObject(Object obj) {
this.students.remove(obj);
}
public List<Student> getObjects() {
return this.students;
}
// 實作創建迭代器物件的具體工廠方法
public AbstractIterator createIterator() {
return new ConcreteIterator(this);
}
}
AbstractIterator:
public interface AbstractIterator {
public void next(); // 移至下一個元素
public boolean isLast(); // 判斷是否為最后一個元素
public void previous(); // 移至上一個元素
public boolean isFirst(); // 判斷是否為第一個元素
public Object getNextItem(); // 獲取下一個元素
public Object getPreviousItem(); // 獲取上一個元素
}
ConcreteIterator:
public class ConcreteIterator implements AbstractIterator{
private List<Student> students;
private int cursor1; // 定義一個游標,用于記錄正向遍歷的位置
private int cursor2; // 定義一個游標,用于記錄逆向遍歷的位置
public ConcreteIterator(ConcreteStoreElement list) {
this.students = list.getObjects(); // 獲取集合物件
cursor1 = 0; // 設定正向遍歷游標的初始值
cursor2 = students.size() - 1; // 設定逆向遍歷游標的初始值
}
public void next() {
if (cursor1 < students.size()) {
cursor1++;
}
}
public boolean isLast() {
return (cursor1 == students.size());
}
public void previous() {
if (cursor2 > -1) {
cursor2--;
}
}
public boolean isFirst() {
return (cursor2 == -1);
}
public Object getNextItem() {
return students.get(cursor1);
}
public Object getPreviousItem() {
return students.get(cursor2);
}
}
好,迭代器的原理就講到這兒啦,下一篇我們來決議一下迭代器在jdk原始碼中是如何應用的,
本文若有不足之處,還請大家多多指正,若有疑問,請小伙伴們私信我,或者評論區留言,
此外推薦一下尚硅谷的Java基礎階段學習資料包括多執行緒、資料、開發工具等等,視頻+原始碼+筆記,資料詳情如下:

非常好的Java學習資料,請大家關注《炫酷的Java》公眾號,輸入javase,即可下載,謝謝大家,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/246539.html
標籤:java
上一篇:2021-01-08
