Java設(shè)計(jì)模式之迭代器模式解析
概述
定義
提供一個(gè)對(duì)象來(lái)順序訪問(wèn)聚合對(duì)象中的一系列數(shù)據(jù),而不暴露聚合對(duì)象的內(nèi)部表示。
結(jié)構(gòu)
迭代器模式 (Iterator Pattern) 主要包含以下角色:
- 抽象聚合(Aggregate)角色:定義存儲(chǔ)、添加、刪除聚合元素以及創(chuàng)建迭代器對(duì)象的接口。
- 具體聚合(Concrete Aggregate)角色:實(shí)現(xiàn)抽象聚合類(lèi),返回一個(gè)具體迭代器的實(shí)例。
- 抽象迭代器(Iterator)角色:定義訪問(wèn)和遍歷聚合元素的接口,通常包含 hasNext()、next() 等方法。
- 具體迭代器(Concrete lterator)角色:實(shí)現(xiàn)抽象迭代器接口中所定義的方法,完成對(duì)聚合對(duì)象的遍歷,記錄遍歷的當(dāng)前位置。
案例實(shí)現(xiàn)
【例】定義一個(gè)可以存儲(chǔ)學(xué)生對(duì)象的容器對(duì)象,將遍歷該容器的功能交由迭代器實(shí)現(xiàn),涉及到的類(lèi)如下:
代碼如下:
- 抽象迭代器角色-迭代器接口,聲明 hasNext()、next() 方法
public interface StudentIterator { // 判斷是否還有元素 boolean hasNext(); // 獲取下一個(gè)元素 Student next(); }
- 具體迭代器角色類(lèi),重寫(xiě)所有的抽象方法
public class StudentIteratorImpl implements StudentIterator { private List<Student> list; private int position = 0; // 記錄遍歷時(shí)的位置 public StudentIteratorImpl(List<Student> list) { this.list = list; } // 判斷是否還有元素 @Override public boolean hasNext() { return position < list.size(); } // 獲取下一個(gè)元素 @Override public Student next() { // 從集合中獲取指定位置的元素 Student currentStudent = list.get(position); position++; return currentStudent; } }
- 抽象容器類(lèi)(抽象聚合角色),包含添加元素,刪除元素,獲取迭代器對(duì)象的方法
public interface StudentAggregate { // 添加學(xué)生功能 void addStudent(Student student); // 刪除學(xué)生功能 void removeStudent(Student student); // 獲取迭代器對(duì)象功能 StudentIterator getStudentIterator(); }
- 具體的容器類(lèi)(具體聚合角色),重寫(xiě)所有的方法
public class StudentAggregateImpl implements StudentAggregate { private List<Student> list = new ArrayList<Student>(); // 學(xué)生列表 // 添加學(xué)生功能 @Override public void addStudent(Student student) { this.list.add(student); } // 刪除學(xué)生功能 @Override public void removeStudent(Student student) { this.list.remove(student); } // 獲取迭代器對(duì)象功能 @Override public StudentIterator getStudentIterator() { // 創(chuàng)建迭代器對(duì)象 return new StudentIteratorImpl(list); } }
- 學(xué)生類(lèi)
public class Student { private String name; private String number; // getter/setter... public Student(String name, String number) { this.name = name; this.number = number; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", number='" + number + '\'' + '}'; } }
- 測(cè)試類(lèi)
public class Client { public static void main(String[] args) { // 創(chuàng)建聚合對(duì)象 StudentAggregateImpl aggregate = new StudentAggregateImpl(); // 添加元素 aggregate.addStudent(new Student("張三", "001")); aggregate.addStudent(new Student("李四", "002")); aggregate.addStudent(new Student("王五", "003")); aggregate.addStudent(new Student("趙六", "004")); /* * 遍歷聚合對(duì)象 */ // 1.獲取迭代器對(duì)象 StudentIterator iterator = aggregate.getStudentIterator(); // 2.遍歷 while (iterator.hasNext()) { // 3.獲取元素 Student student = iterator.next(); System.out.println(student.toString()); } } }
輸出
Student{name='張三', number='001'}
Student{name='李四', number='002'}
Student{name='王五', number='003'}
Student{name='趙六', number='004'}
優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
- 它支持以不同的方式遍歷一個(gè)聚合對(duì)象,在同一個(gè)聚合對(duì)象上可以定義多種遍歷方式。在迭代器模式中只需要用一個(gè)不同的迭代器來(lái)替換原有迭代器即可改變遍歷算法,我們也可以自己定義迭代器的子類(lèi)以支持新的遍歷方式。
- 迭代器簡(jiǎn)化了聚合類(lèi)。由于引入了迭代器,在原有的聚合對(duì)象中不需要再自行提供數(shù)據(jù)遍歷等方法,這樣可以簡(jiǎn)化聚合類(lèi)的設(shè)計(jì)。
- 在迭代器模式中,由于引入了抽象層,增加新的聚合類(lèi)和迭代器類(lèi)都很方便,無(wú)須修改原有代碼,滿足“開(kāi)閉原則”的要求。
缺點(diǎn)
- 增加了類(lèi)的個(gè)數(shù),這在一定程度上增加了系統(tǒng)的復(fù)雜性。
使用場(chǎng)景
- 當(dāng)需要為聚合對(duì)象提供多種遍歷方式時(shí)。
- 當(dāng)需要為遍歷不同的聚合結(jié)構(gòu)提供一個(gè)統(tǒng)一的接口時(shí)。
- 當(dāng)訪問(wèn)一個(gè)聚合對(duì)象的內(nèi)容而無(wú)須暴露其內(nèi)部細(xì)節(jié)的表示時(shí)。
JDK源碼解析-集合類(lèi)
迭代器模式在 java 的很多集合類(lèi)中被廣泛應(yīng)用,接下來(lái)看看 java 源碼中是如何使用迭代器模式的。
List<String> list = new ArrayList<>(); Iterator<String> iterator = list.iterator(); // list.iterator()方法返回的肯定是Iterator接口的子實(shí)現(xiàn)類(lèi)對(duì)象 while (iterator.hasNext()) { System.out.println(iterator.next()); }
看完這段代碼是不是很熟悉,與我們上面代碼基本類(lèi)似。單列集合都使用到了迭代器,我們以 ArrayList 舉例來(lái)說(shuō)明:
- List:抽象聚合類(lèi)
- ArrayList:具體的聚合類(lèi)
- Iterator:抽象迭代器
- list.iterator():返回的是實(shí)現(xiàn)了 Iterator 接口的具體迭代器對(duì)象(在 ArrayList 中就是內(nèi)部類(lèi) Itr)
具體的來(lái)看看 ArrayList 的代碼實(shí)現(xiàn):
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { public Iterator<E> iterator() { // 返回的肯定是Iterator的子實(shí)現(xiàn)類(lèi)對(duì)象 return new Itr(); } || \/ // 內(nèi)部類(lèi)Itr 實(shí)現(xiàn)了Iterator接口 并且重寫(xiě)了 hasNext() 和 next() 方法。 private class Itr implements Iterator<E> { int cursor; // 下一個(gè)要返回元素的索引 int lastRet = -1; // 上一個(gè)返回元素的索引 int expectedModCount = modCount; Itr() {} // 判斷是否還有元素 public boolean hasNext() { return cursor != size; } // 獲取下一個(gè)元素 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]; } ... }
這部分代碼還是比較簡(jiǎn)單,大致就是在 iterator 方法中返回了一個(gè)實(shí)例化的 Iterator 對(duì)象,Itr 是一個(gè)內(nèi)部類(lèi),它實(shí)現(xiàn)了 Iterator 接口并重寫(xiě)了其中的抽象方法。
注意:
當(dāng)我們?cè)谑褂?java 開(kāi)發(fā)的時(shí)候,想使用迭代器模式的話,只要讓我們自己定義的容器類(lèi)實(shí)現(xiàn) java.util.Iterable 并實(shí)現(xiàn)其中的 iterator() 方法使其返回一個(gè) java.util.Iterator 的實(shí)現(xiàn)類(lèi)就可以了。
到此這篇關(guān)于Java設(shè)計(jì)模式之迭代器模式解析的文章就介紹到這了,更多相關(guān)Java的迭代器模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java實(shí)現(xiàn)簡(jiǎn)單音樂(lè)播放器
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)單音樂(lè)播放器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06Java 數(shù)據(jù)庫(kù)時(shí)間返回前端顯示錯(cuò)誤(差8個(gè)小時(shí))的解決方法
本文主要介紹了Java 數(shù)據(jù)庫(kù)時(shí)間返回前端顯示錯(cuò)誤(差8個(gè)小時(shí))的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08使用Spring CROS解決項(xiàng)目中的跨域問(wèn)題詳解
這篇文章主要介紹了使用Spring CROS解決項(xiàng)目中的跨域問(wèn)題詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01Java Web項(xiàng)目創(chuàng)建并實(shí)現(xiàn)前后端交互
本文主要介紹了Java Web項(xiàng)目創(chuàng)建并實(shí)現(xiàn)前后端交互,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07Postman form-data、x-www-form-urlencoded的區(qū)別及說(shuō)明
這篇文章主要介紹了Postman form-data、x-www-form-urlencoded的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03Java動(dòng)態(tài)代理和AOP應(yīng)用示例
這篇文章主要介紹了Java動(dòng)態(tài)代理和AOP應(yīng)用,結(jié)合實(shí)例形式分析了java動(dòng)態(tài)代理在AOP面向切面編程中的相關(guān)操作技巧與使用注意事項(xiàng),需要的朋友可以參考下2019-07-07詳解MyBatisPlus如何實(shí)現(xiàn)分頁(yè)和查詢操作
這篇文章主要為大家詳細(xì)介紹了MyBatisPlus是如何實(shí)現(xiàn)分頁(yè)和查詢操作的,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)有一定的幫助,需要的可以參考一下2022-05-05