基本需求:
- 展示一個學校的結構,比如一個學校下面有多個學院,學院下面有多個系,對其節點主要是遍歷,與組合模式略有不同
傳統方案:
- 學校<-學院<-系 依次繼承
- 這種方式,在一個頁面中展示出學校的院系組成,一個學校有多個學院,一個學院有多個系,因此這種方案,不能很好實現的遍歷的操作,並且他們之間也沒有繼承關係,使用繼承並不合適
基本介紹:
-
迭代器模式(Iterator)是常用的設計模式,屬於行為型模式,這種模式用於順序訪問集合物件的元素,不需要知道集合物件的底層表示
-
如果我們的集合元素是用不同的方式實現的,有陣列,還有java的集合類,或者還有其他方式,當客戶端要遍歷這些集合元素的時候就要使用多種遍歷方式,而且還會暴露元素的內部結構,可以考慮使用迭代器模式解決
-
迭代器模式提供一種遍歷集合元素的統一介面,用一致的方法遍歷集合元素,不需要知道集合物件的底層表示,即:不暴露其內部的結構
-
把在元素之間遊走的責任交給迭代器,而不是聚合物件
-
由於迭代器模式將儲存資料和遍歷資料的職責分離,增加新的聚合類需要對應增加新的迭代器類,類的個數成對增加,這在一定程度上增加了系統的複雜性
-
UML類圖(原理)
- 說明
- Iterator:迭代器介面,直接使用JDK提供的即可提供,含有hasNext, next, remove
- ConcreteIterator:具體的迭代器類,進行元素迭代,其內部元素的以不同的方式進行儲存,例如陣列、list等
- Aggregate:一個統一的聚合介面,將客戶端和具體聚合解耦,進行元素的儲存
- ConcreteAggreage:具體的聚合持有物件集合,並提供一個方法,返回一個迭代器,該迭代器可以正確遍歷集合,和ConcreteIterator一一對應
- Element:集合內部所儲存的元素
- 實際情況中一般將ConcreteIterator作為內部類放入ConcreteAggreage類中,直接省去了元素集合elementes的傳遞
- 說明
-
UML類圖(案例)
- 說明
- OutputImpl:用於輸出資訊的輔助類
- 說明
-
程式碼實現
-
迭代器類不作為持有迭代集合類的內部類
-
@Data @AllArgsConstructor public class Department { // 迭代器內部元素 private String name; private String description; }
-
public class ComputerCollegeIterator implements Iterator { // 計算機學院迭代器,元素使用陣列儲存 一般會將迭代器實現類作為需要迭代物件的內部類 private Department[] departments; // 當前位置指標 private int index = 0; public ComputerCollegeIterator(Department[] departments) { this.departments = departments; } // 判斷是否有下一個元素 @Override public boolean hasNext() { return !(this.index >= this.departments.length); } // 返回下一個元素 @Override public Department next() { return this.departments[this.index++]; } @Override public void remove() { // 移除方法空實現 } }
-
public class InfoCollegeIterator implements Iterator { // 資訊工程學院迭代器,元素使用List集合儲存 一般會將迭代器實現類作為需要迭代物件的內部類 private List<Department> departments; // 當前位置指標 private int index = 0; public InfoCollegeIterator(List<Department> departments) { this.departments = departments; } // 判斷是否有下一個元素 @Override public boolean hasNext() { return !(this.index >= this.departments.size()); } // 返回下一個元素 @Override public Department next() { return this.departments.get(this.index++); } @Override public void remove() { // 移除方法空實現 } }
-
public interface College { // 學院介面 // 獲取學院名稱 String getName(); // 給學院內部新增系 void addDepartment(String name, String description); // 獲取該學院所對應的迭代器 Iterator createIterator(); } // 實現類一 計算機學院 class ComputerCollege implements College { // 儲存內部元素的集合,用於獲取迭代器 private Department[] departments; // 當前元素位置指標 private int index; public ComputerCollege() { this.departments = new Department[5]; this.index = 0; addDepartment("Java專業", "Java專業 "); addDepartment("PHP專業", "PHP專業 "); addDepartment("大資料專業", "大資料專業"); } @Override public String getName() { return "計算機學院"; } @Override public void addDepartment(String name, String description) { Department department = new Department(name, description); this.departments[this.index++] = department; } @Override public Iterator createIterator() { return new ComputerCollegeIterator(this.departments); } } // 實現類二 資訊工程學院 class InfoCollege implements College { // 儲存內部元素的集合,用於獲取迭代器 private List<Department> departments; public InfoCollege() { this.departments = new ArrayList<Department>(); addDepartment("資訊保安專業", "資訊保安專業"); addDepartment("網路安全專業", "網路安全專業"); addDepartment("伺服器安全專業", "伺服器安全專業"); } @Override public String getName() { return "資訊工程學院"; } @Override public void addDepartment(String name, String description) { this.departments.add(new Department(name, description)); } @Override public Iterator createIterator() { return new InfoCollegeIterator(this.departments); } }
-
public class OutputImpl { // 輸出迭代器元素內部的實現類 private List<College> colleges; public OutputImpl(List<College> colleges) { this.colleges = colleges; } public void printCollege() { // 獲取List集合內部的迭代器 Iterator<College> iterator = colleges.iterator(); while (iterator.hasNext()) { College college = iterator.next(); System.out.println("======" + college.getName() + "======"); // 獲取學院內部系的迭代器進行迭代輸出 而不需要知道元素再內部以什麼形式的集合存在,統一了遍歷方式 printDepartment(college.createIterator()); } } private void printDepartment(Iterator iterator) { while (iterator.hasNext()) { Department department = (Department) iterator.next(); if (null != department) { System.out.println(department.getName() + "-----" + department.getDescription()); } } } }
-
public class Client { public static void main(String[] args) { // 建立學院的集合 List<College> colleges = new ArrayList<College>(); colleges.add(new ComputerCollege()); colleges.add(new InfoCollege()); // 建立輸出類 並迭代輸出學院及其下面的系 OutputImpl output = new OutputImpl(colleges); output.printCollege(); } }
-
-
迭代器類作為持有迭代集合類的內部類
-
// 實現類一 計算機學院 public class ComputerCollege implements College { // 儲存內部元素的集合,用於獲取迭代器 private Department[] departments; // 當前元素位置指標 private int index; public ComputerCollege() { this.departments = new Department[5]; this.index = 0; addDepartment("Java專業", "Java專業 "); addDepartment("PHP專業", "PHP專業 "); addDepartment("大資料專業", "大資料專業"); } @Override public String getName() { return "計算機學院"; } @Override public void addDepartment(String name, String description) { Department department = new Department(name, description); this.departments[this.index++] = department; } @Override public Iterator createIterator() { return new ComputerCollegeIterator(); } // 迭代器類作為持有迭代集合類的內部類 private class ComputerCollegeIterator implements Iterator { // 計算機學院迭代器,元素使用陣列儲存 一般會將迭代器實現類作為需要迭代物件的內部類 // 當前位置指標 private int index = 0; // 判斷是否有下一個元素 直接使用上層類的元素集合即可 @Override public boolean hasNext() { return !(this.index >= ComputerCollege.this.departments.length); } // 返回下一個元素 直接使用上層類的元素集合即可 @Override public Department next() { return ComputerCollege.this.departments[this.index++]; } @Override public void remove() { // 移除方法空實現 } } }
-
// 實現類二 資訊工程學院 public class InfoCollege implements College { // 儲存內部元素的集合,用於獲取迭代器 private List<Department> departments; public InfoCollege() { this.departments = new ArrayList<Department>(); addDepartment("資訊保安專業", "資訊保安專業"); addDepartment("網路安全專業", "網路安全專業"); addDepartment("伺服器安全專業", "伺服器安全專業"); } @Override public String getName() { return "資訊工程學院"; } @Override public void addDepartment(String name, String description) { this.departments.add(new Department(name, description)); } @Override public Iterator createIterator() { return new InfoCollegeIterator(); } // 迭代器類作為持有迭代集合類的內部類 private class InfoCollegeIterator implements Iterator { // 資訊工程學院迭代器,元素使用List集合儲存 一般會將迭代器實現類作為需要迭代物件的內部類 // 當前位置指標 private int index = 0; // 判斷是否有下一個元素 直接使用上層類的元素集合即可 @Override public boolean hasNext() { return !(this.index >= InfoCollege.this.departments.size()); } // 返回下一個元素 直接使用上層類的元素集合即可 @Override public Department next() { return InfoCollege.this.departments.get(this.index++); } @Override public void remove() { // 移除方法空實現 } } }
-
-
jdk原始碼:
-
在jdk的ArrayList原始碼中就使用到了迭代器模式
-
UML類圖
-
說明
-
List就是充當了聚合介面,含有一個iterator()方法,返回一個迭代器物件
-
ArrayList是實現聚合介面List的子類,實現了iterator()
-
ArrayList內部的elementData屬性就是存放元素的集合,是一個陣列Object[]
-
Itr充當具體實現迭代器Iterator的類,作為ArrayList內部類
-
Iterator介面JDk提供
-
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { // 儲存元素的集合 transient Object[] elementData; // 實現獲取迭代器方法 public Iterator<E> iterator() { return new Itr(); } /** * An optimized version of AbstractList.Itr */ // 作為ArrayList內部類 實現迭代器Iterator private class Itr implements Iterator<E> { ...... } }
-
注意事項:
- 提供一個統一的方法遍歷物件,客戶不用再考慮聚合的型別,使用一種方法就可以遍歷物件了
- 隱藏了聚合的內部結構,客戶端要遍歷聚合的時候只能取到迭代器,而不會知道聚合的具體組成
- 提供了一種設計思想,就是一個類應該只有一個引起變化的原因(叫做單一責任原則)。在聚合類中,我們把迭代器分開,就是要把管理物件集合和遍歷物件集合的責任分開,這樣一來集合改變的話,隻影響到聚合物件。而如果遍歷方式改變的話,隻影響到了迭代器
- 當要展示一組相似物件,或者遍歷一組相同物件時使用, 適合使用迭代器模式
- 每個聚合物件都要一個迭代器,會生成多個迭代器不好管理類