摘要:迭代器模式屬于行為型模式的一種,提供一種方法訪問一個容器中各個元素,而又不需要暴露該對象的內部細節。迭代器模式把在元素之間游走的責任交給迭代器,而不是聚合對象。
概述迭代器模式(Iterator Pattern)屬于行為型模式的一種,提供一種方法訪問一個容器中各個元素,而又不需要暴露該對象的內部細節。
迭代器模式聽起來可能感覺很陌生,但是實際上,迭代器模式是所有設計模式中最簡單也是最常用的設計模式,正是因為太常用了,所以導致很多人忽略了它的存在。
在實際的開發過程中,我們可能需要針對不同的需求,可能需要以不同的方式來遍歷整個整合對象,但又不希望在聚合對象的抽象接口層中充斥著各種不同的便利操作。這個時候我們就需要這樣一種東西,它應該具備如下三個功能:
能夠便利一個聚合對象。
我們不需要了解聚合對象的內部結構。
能夠提供多種不同的遍歷方式。
迭代器模式: 把在元素之間游走的責任交給迭代器,而不是聚合對象。簡化了聚合的接口和實現,讓聚合更專注在它所應該專注的事情上,這樣做更加符合單一責任原則。
UML結構圖
模式結構
Iterator(抽象迭代器): 具體迭代器需要實現的接口,提供了游走聚合對象元素之間的方法
ConcreteIterator(具體迭代器): 對具體的聚合對象進行遍歷,每一個聚合對象都應該對應一個具體的迭代器。
Aggregate(抽象聚合類): 存儲和管理元素對象,聲明了createIterator()用于創建一個迭代器對象,充當抽象迭代器工廠角色
ConcreteAggregate(具體聚合類): 實現了在抽象聚合類中聲明的createIterator(),該方法返回一個與該具體聚合類對應的具體迭代器ConcreteIterator實例。
案例UML圖如下:
1.先定義抽象迭代器``
interface Iterator{ //判斷是否有還有下一個元素 boolean hasNext(); //取出下一個對象 E next(); }
2.在定義一個具體迭代器對象,實現了Iterator中的方法
class MusicIteratorimplements Iterator { private E[] es; private int position = 0; public MusicIterator(E[] es) { this.es = es; } @Override public boolean hasNext() { return position != es.length; } @Override public E next() { E e = es[position]; position += 1; return e; } }
3.接下來定義抽象聚合類(常為 Collection , List , Set 等)
interface AbstractList{ void add(E e); Iterator createIterator(); }
4.最后創建具體聚合類 (常為 ArrayList , HashSet 等,是抽象聚合類的實現類)
class MusicList implements AbstractList{ private String[] books = new String[5]; private int position = 0; @Override public void add(String name) { books[position] = name; position += 1; } @Override public Iterator createIterator() { return new MusicIterator<>(books); } }
5.創建測試工程
public class Client { public static void main(String[] args) { AbstractListlist = new MusicList(); list.add("涼涼"); list.add("奇談"); list.add("紅顏"); list.add("伴虎"); list.add("在人間"); Iterator iterator = list.createIterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } }
6.運行效果
涼涼 奇談 紅顏 伴虎 在人間
至此一個簡單的迭代器就完成了,實現了對容器的遍歷。可以看到迭代器在Client中遍歷時根本不需要知道他底層的實現,只需要通過迭代器來遍歷就可以了。
JDK中應用上文介紹了自己實現一個簡單的迭代器,看完的應該就不陌生了,它其實在JAVA的很多集合類中被廣泛應用,接下來看看JAVA源碼中是如何使用迭代器模式的。
Listlist = new ArrayList<>(); Iterator iterator = list.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); }
看完這段代碼是不是很熟悉,與我們上文代碼基本類似
List:抽象聚合器
ArrayList:具體的聚合類
Iterator:抽象迭代器
list.iterator():返回的是實現了Iterator接口的具體迭代器對象
接下來看下ArrayList中的iterator是如何實現的
public Iteratoriterator() { return new Itr(); } private class Itr implements Iterator { 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(); } }
這部分代碼還是比較簡單,大致就是在iterator方法中返回了一個實例化的Iterator對象。Itr是一個內部類,它實現了Iterator接口并實現了其中的方法。
當我們在使用JAVA開發的時候,想使用迭代器模式的話,只要讓我們自己定義的容器類實現java.util.Iterable并實現其中的iterator方法使其返回一個java.util.Iterator的實現類就可以了。
總結迭代器模式與集合共生共死的,一般來說,我們只要實現一個集合,就需要同時提供這個集合的迭代器,就像java中的Collection,List、Set、Map等,這些集合都有自己的迭代器。假如我們要實現一個這樣的新的容器,當然也需要引入迭代器模式,給我們的容器實現一個迭代器。但在絕大多數情況,我們是不需要自己實現的,基本都內置了
優點
支持不同方式遍歷一個聚合對象,在同一個聚合上可以有多個遍歷。
簡化了聚合類。由于引入了迭代器,在原有的聚合對象中不需要再自行提供數據遍歷等方法。
在迭代器模式中,由于引入了抽象層,增加新的聚合類和迭代器類都很方便,無須修改原有代碼
缺點
由于迭代器模式將存儲數據和遍歷數據的職責分離,增加新的聚合類需要對應增加新的迭代器類,類的個數成對增加,這在一定程度上增加了系統的復雜性。
抽象迭代器的設計難度較大,需要充分考慮到系統將來的擴展,例如JDK內置迭代器Iterator就無法實現逆向遍歷,如果需要實現逆向遍歷,只能通過其子類ListIterator等來實現,而ListIterator迭代器無法用于操作Set類型的聚合對象。在自定義迭代器時,創建一個考慮全面的抽象迭代器并不是件很容易的事情。
說點什么全文代碼:https://gitee.com/battcn/design-pattern/tree/master/Chapter14/battcn-iterator
個人QQ:1837307557
battcn開源群(適合新手):391619659
微信公眾號:battcn(歡迎調戲)
福利關注公眾號:battcn,回復springboot即可獲得
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/70670.html
摘要:備忘錄模式常常與命令模式和迭代子模式一同使用。自述歷史所謂自述歷史模式實際上就是備忘錄模式的一個變種。在備忘錄模式中,發起人角色負責人角色和備忘錄角色都是獨立的角色。 備忘錄模式(Memento Pattern)屬于行為型模式的一種,在不破壞封裝特性的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態。這樣就可以將該對象恢復到原先保存的狀態。 概述 備忘錄模式又叫做快照模式(...
摘要:用專業的話來講設計模式是一套被反復使用多數人知曉的經過分類編目的代碼設計經驗的總結創建型模式,共五種工廠方法模式抽象工廠模式單例模式建造者模式原型模式。工廠方法模式的擴展性非常優秀。工廠方法模式是典型的解耦框架。 前言 最近一直在Java方向奮斗《終于,我還是下決心學Java后臺了》,今天抽空開始學習Java的設計模式了。計劃有時間就去學習,你這么有時間,還不來一起上車嗎? 之所以要學...
閱讀 2016·2021-11-12 10:36
閱讀 1866·2021-11-09 09:49
閱讀 2593·2021-11-04 16:12
閱讀 1144·2021-10-09 09:57
閱讀 3235·2019-08-29 17:24
閱讀 1909·2019-08-29 15:12
閱讀 1272·2019-08-29 14:07
閱讀 1285·2019-08-29 12:53