迭代器設計模式知識概括
迭代器設計模式簡介
學校院系展示需求:
- 編寫程式展示一個學校院系結構:需求是這樣,要在一個頁面中展示出學校的院系組成,一個學校有多個學院,一個學院有多個系。 如圖:
傳統的方式的問題分析:
- 將學院看做是學校的子類,系是學院的子類,這樣實際上是站在組織大小來進行分層次的
- 實際上我們的要求是 : 在一個頁面中展示出學校的院系組成,一個學校有多個學院,一個學院有多個系, 因此這種方案,不能很好實現的遍歷的操作
- 假如計算機學院的院系儲存在陣列中,資訊工程學院的院系儲存在集合中,我們要怎麼才能定義一個統一的規範,來遍歷不同儲存結構下的院系。解決方案: => 迭代器模式
迭代器模式基本介紹:
- 迭代器模式(Iterator Pattern) 是常用的設計模式,屬於行為型模式
- 如果我們的集合元素是用不同的方式實現的,有陣列,還有java的集合類,或者還有其他方式,當客戶端要遍歷這些集合元素的時候就要使用多種遍歷方式,而且還會暴露元素的內部結構,可以考慮使用迭代器模式解決。
- 迭代器模式,提供一種遍歷集合元素的統一介面,用一致的方法遍歷集合元素,對於使用者來說,不需要知道集合物件的底層表示,即:不暴露集合的內部結構
迭代器模式的原理類圖:
- Iterator :迭代器介面,由 JDK提供,該介面定義了三個用於遍歷集合(陣列)的方法:hasNext()、next()、remove()
- ConcreteIterator:具體的迭代器類,實現具體的迭代邏輯
- Aggregate:一個統一的聚合介面,將客戶端和具體的 Aggregate 實現類解耦
- ConcreteAggreage :具體的聚合實現類,該類持有物件集合(Element),並提供一個方法,返回一個迭代器, 該迭代器可以正確遍歷集合
- Client:客戶端,通過 Iterator 和 Aggregate 依賴其對應的子類
迭代器模式解決學校院系展示需求
簡介:
- 應用例項要求:編寫程式展示一個學校院系結構: 需求是這樣, 要在一個頁面中展示出學校的院系組成, 一個學校有多個學院,一個學院有多個系
- 類圖:
- 程式碼實現:
Department:實體類,用於表示學院的系
//系
public class Department {
private String name;
private String desc;
public Department(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
ComputerCollegeIterator:計算機院系的迭代器,該類實現了 Iterator 介面,用於迭代計算機學院的系
public class ComputerCollegeIterator implements Iterator {
// 這裡我們需要Department 是以怎樣的方式存放=>陣列
Department[] departments;
int position = 0; // 遍歷的位置
public ComputerCollegeIterator(Department[] departments) {
this.departments = departments;
}
// 判斷是否還有下一個元素
@Override
public boolean hasNext() {
if (position >= departments.length || departments[position] == null) {
return false;
} else {
return true;
}
}
@Override
public Object next() {
Department department = departments[position];
position += 1;
return department;
}
// 刪除的方法,預設空實現
@Override
public void remove() {
}
}
InfoColleageIterator:資訊院系的迭代器,該類實現了 Iterator 介面,用於迭代資訊學院的系
public class InfoColleageIterator implements Iterator {
List<Department> departmentList; // 資訊工程學院是以List方式存放系
int index = -1;// 索引
public InfoColleageIterator(List<Department> departmentList) {
this.departmentList = departmentList;
}
// 判斷list中還有沒有下一個元素
@Override
public boolean hasNext() {
if (index >= departmentList.size() - 1) {
return false;
} else {
index += 1;
return true;
}
}
@Override
public Object next() {
return departmentList.get(index);
}
// 空實現remove
@Override
public void remove() {
}
}
College:學院的聚合介面
public interface College {
public String getName();
// 增加系的方法
public void addDepartment(String name, String desc);
// 返回一個迭代器,遍歷
public Iterator createIterator();
}
ComputerCollege:計算機學院的聚合介面實現類,該類聚合了 Department[] 陣列,並提供訪問 Department[] 陣列的迭代器
public class ComputerCollege implements College {
Department[] departments;
int numOfDepartment = 0;// 儲存當前陣列的物件個數
public ComputerCollege() {
departments = new Department[5];
addDepartment("Java專業", " Java專業 ");
addDepartment("PHP專業", " PHP專業 ");
addDepartment("大資料專業", " 大資料專業 ");
numOfDepartment = 3;
}
@Override
public String getName() {
return "計算機學院";
}
@Override
public void addDepartment(String name, String desc) {
Department department = new Department(name, desc);
departments[numOfDepartment] = department;
numOfDepartment += 1;
}
@Override
public Iterator createIterator() {
return new ComputerCollegeIterator(departments);
}
}
InfoCollege:資訊學院的聚合介面實現類,該類聚合了 List 集合,並提供訪問 List 集合的迭代器
public class InfoCollege implements College {
List<Department> departmentList;
public InfoCollege() {
departmentList = new ArrayList<Department>();
addDepartment("資訊保安專業", " 資訊保安專業 ");
addDepartment("網路安全專業", " 網路安全專業 ");
addDepartment("伺服器安全專業", " 伺服器安全專業 ");
}
@Override
public String getName() {
return "資訊工程學院";
}
@Override
public void addDepartment(String name, String desc) {
Department department = new Department(name, desc);
departmentList.add(department);
}
@Override
public Iterator createIterator() {
return new InfoColleageIterator(departmentList);
}
}
OutPutImpl:為 Client 層提供遍歷輸出學院系的方法
public class OutPutImpl {
// 學院集合
List<College> collegeList;
public OutPutImpl(List<College> collegeList) {
this.collegeList = collegeList;
}
// 遍歷所有學院,然後呼叫printDepartment 輸出各個學院的系
public void printCollege() {
// 從collegeList 取出所有學院, Java 中的 List 已經實現Iterator
Iterator<College> iterator = collegeList.iterator();
while (iterator.hasNext()) {
// 取出一個學院
College college = iterator.next();
System.out.println("=== " + college.getName() + "=====");
printDepartment(college.createIterator()); // 得到對應迭代器
}
}
// 輸出學院的系
public void printDepartment(Iterator iterator) {
while (iterator.hasNext()) {
Department d = (Department) iterator.next();
System.out.println(d.getName());
}
}
}
Client:測試程式碼
public class Client {
public static void main(String[] args) {
// 建立學院
List<College> collegeList = new ArrayList<College>();
ComputerCollege computerCollege = new ComputerCollege();
InfoCollege infoCollege = new InfoCollege();
collegeList.add(computerCollege);
collegeList.add(infoCollege);
OutPutImpl outPutImpl = new OutPutImpl(collegeList);
outPutImpl.printCollege();
}
}
總結:
- 院系資料真實存放在 ComputerCollege 和 InfoCollege 中,如果想要遍歷院系,需要將院系作為引數傳入ComputerCollegeIterator 和 InfoColleageIterator 中,獲得迭代器,進行迭代
JDK ArrayList 原始碼分析
原理類圖分析:
- ArrayList 的內部類 Itr 充當了具體實現迭代器 Iterator 的類
- List 就是充當了聚合介面, 含有一個 iterator() 方法, 該方法返回一個迭代器物件
- ArrayList 是實現聚合介面 List 的子類, 實現了 iterator() 方法
- Iterator 介面系統(JDK)提供
- 迭代器模式解決了不同集合(ArrayList,LinkedList) 統一遍歷問題
原始碼追蹤:
Iterator 介面中定義的方法
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
在 List 介面中定義了獲取 iterator 的抽象方法,即 List 充當了聚合介面
public interface List<E> extends Collection<E> {
// ...
Iterator<E> iterator();
// ...
在 ArrayList 中實現了 iterator 方法
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
// ...
public Iterator<E> iterator() {
return new Itr();
}
// ...
Itr 實現了 Iterator 介面,為 ArrayList 的內部類,在 Itr 中,直接使用 ArrayList 中用於存放資料的 Object[] 陣列,通過 size 屬性標識集合元素個數
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
迭代器模式的注意事項
迭代器模式的注意事項和細節:
- 優點:
①提供一個統一的方法遍歷物件,客戶不用再考慮聚合的型別,使用一種方法就可以遍歷物件了。
②隱藏了聚合的內部結構,客戶端要遍歷聚合的時候只能取到迭代器,而不會知道聚合的具體組成。
③提供了一種設計思想,就是一個類應該只有一個引起變化的原因(叫做單一責任原則)。在聚合類中,我們把迭代器分開,就是要把管理物件集合和遍歷物件集合的責任分開,這樣一來集合改變的話,隻影響到聚合物件。而如果遍歷方式改變的話,隻影響到了迭代器。
④當要展示一組相似物件,或者遍歷一組相同物件時使用,適合使用迭代器模式 - 缺點:
①每個聚合物件都要一個迭代器,會生成多個迭代器不好管理類
相關文章
- 直譯器設計模式知識概括設計模式
- 觀察者設計模式知識概括設計模式
- 備忘錄設計模式知識概括設計模式
- 設計模式(十七)迭代器模式設計模式
- js設計模式--迭代器模式JS設計模式
- JS設計模式(迭代器模式)JS設計模式
- 設計模式之迭代器模式設計模式
- 設計模式(十六)迭代器設計模式
- golang設計模式之迭代器模式Golang設計模式
- Javascript設計模式之迭代器模式JavaScript設計模式
- 簡說設計模式——迭代器模式設計模式
- JavaScript 設計模式(六) 迭代器模式JavaScript設計模式
- 極簡設計模式-迭代器模式設計模式
- Java設計模式8:迭代器模式Java設計模式
- HTML知識概括HTML
- 基本的設計模式概括設計模式
- 23天設計模式之迭代器模式設計模式
- javascript設計模式 之 4 迭代器模式JavaScript設計模式
- C#設計模式之迭代器模式C#設計模式
- 設計模式-行為篇(迭代器模式)設計模式
- 23種設計模式之迭代器模式設計模式
- Python知識概括Python
- 16.java設計模式之迭代器模式Java設計模式
- Rust語言之GoF設計模式:迭代器模式RustGo設計模式
- 17、Python與設計模式–迭代器模式Python設計模式
- 設計模式--迭代器模式Iterator(行為型)設計模式
- C#設計模式系列:迭代器模式(Iterator)C#設計模式
- JAVA設計模式之 迭代器模式【Iterator Pattern】Java設計模式
- PHP設計模式漫談之迭代器模式PHP設計模式
- 設計模式知識梳理(1) 設計模式概述設計模式
- 軟體設計模式學習(二十)迭代器模式設計模式
- 軟體設計模式系列之十八——迭代器模式設計模式
- 設計模式學習筆記之迭代器模式設計模式筆記
- 設計模式的征途—21.迭代器(Iterator)模式設計模式
- 「補課」進行時:設計模式(13)——迭代器模式設計模式
- 【設計模式基礎】行為模式 - 7 - 迭代器(Iterator)設計模式
- 設計模式(二十四)----行為型模式之迭代器模式設計模式
- 《JavaScript設計模式與開發實踐》模式篇(4)—— 迭代器模式JavaScript設計模式