1. 程式人生 > >設計模式01——Iterator模式

設計模式01——Iterator模式

定義

迭代器(Iterator)模式,從其英文單詞可以看出,有反覆做某件事的意思。迭代器模式常用於資料集合中,對資料集合中的資料按照順序進行遍歷。它能提供一種方法訪問一個容器物件中各個元素,而又不暴露該物件的內部細節。

問題引入

假設我們有一個書架,假設書架可以按照順序放置無數本書,現在有一個需求,那就是遍歷書架裡面的所有的書籍,將書籍的名稱打印出來。
這裡寫圖片描述

常規的解決辦法

一般情況下,我們在用程式碼來解決該問題的時候,都是想到使用for迴圈,對書架中的每一本書進行迴圈遍歷,然後輸出名稱。這是一種比較常規的做法,考慮的問題就是為了遍歷書架中的書籍,並使用變數i來記錄當前遍歷到哪一本書了,以及將指標指向下一本書,虛擬碼如下:

List<Book> books = new ArrayList<>();
books.add(new Book("深入理解Java虛擬機器"));
books.add(new Book("深入分析Java Web技術內幕"));
books.add(new Book("Java程式設計思想"));
books.add(new Book("Linux就該這麼學"));
for (int i = 0; i < books.size(); i++) {
    System.out.println(books.get(i).getName());
}

這裡的for

語句中的i++的作用是將i的值在每一次迴圈之後就自增1,使得在遍歷的過程中就可以訪問集合中的下一本書籍,下下一本書籍,再下下一本書籍,直到遍歷完所有的書籍。如果我們考慮將i的作用進行抽象化,使其通用化,那麼就可以形成迭代器模式。

從List中獲取啟發

說到迭代器設計模式,大家肯定會想到java.util包中的集合,是的,Java中集合類中運用到了迭代器設計模式,那麼,我們在學習迭代器設計模式的時候,完全可以通過去學習集合的原始碼來學習迭代器設計模式,下面,我將從ArrayList出發,探究一下在ArrayList中如何運用的迭代器設計模式。
作為集合類的頂級介面,Collection

介面繼承了Iterable介面,Iterable介面的子介面或者實現類都具備迭代和遍歷的功能,那麼List介面繼承自Collection,自然也是具備基本的迭代功能的,那麼我們從List出發,來探究迭代器模式的運用。
List介面中有一個重寫自Collectioniterator()方法,它的返回值是一個Iterator介面的實現類物件。
這裡寫圖片描述
那麼我們接著看ArrayList類,它實現了List介面,也實現了List介面中的iterator()方法。
這裡寫圖片描述
那麼,針對例項化ArrayList的時候傳入的具體的泛型,可以生成其對應的迭代器,也就是說,上圖中new語句後面的Itr()創造出來的迭代器物件肯定是針對傳入的泛型的迭代器物件。我們繼續閱讀程式碼,發現ItrArrayList的私有內部類,它還實現了Iterator介面,也實現了基本的hasNext()方法和next()方法。
這裡寫圖片描述
因為ItrArrayList的內部類,那麼Itr可以操作ArrayList的成員變數,而ArrayList作為集合,它內部的元素是儲存在變數名為elementDataObject陣列中的,整個遍歷的過程就是針對這個陣列進行遍歷的。
分析完原始碼,我們也許還是有些迷糊,那麼我們需要藉助UML類圖來描述這些介面或者類之間的關係了。
這裡寫圖片描述
從上圖可以看出,List介面中有建立Iterator介面的實現類物件的抽象方法,而ArrayList實現了List介面,而Itr類實現了Iterator介面,且其擁有ArrayList的元素陣列,可以針對該陣列進行一系列的操作,比如遍歷。類圖可以很清晰表表現出類與類之間的關係,不太熟悉的可以去學習一下UML類圖。

手動實現迭代器設計模式

List中獲取到迭代器設計模式實現的靈感,那麼我們需要自己手動實現自己的迭代器模式,來解決文章開始引入的遍歷書架的問題。首先,我們根據List中採用的迭代器設計模式,我們需要一個集合介面Aggregate(有“使聚集”、“聚合”的意思),該集合介面中有建立迭代器介面Iterator實現類物件的抽象方法iterator,這個迭代器介面有hasNextnext方法,用來判斷集合是否還有元素以及獲取集合元素,我們還需要具體的集合實現類,也就是具體的書架,用來承載書籍,該實現類實現了Aggregate集合的iterator方法,最後,我們還需要實現迭代器介面的具體類,它持有集合的具體的實現類,還實現了hasNextnext方法。我們將類圖設計如下所示:
這裡寫圖片描述
根據類圖,我們可以很輕鬆地設計出基本的迭代器設計模式及的程式碼,主要程式碼如下所示:

  • 集合介面Aggregate
package cn.itlemon.design.pattern.chapter01.iterator.example;

/**
 * 是需要遍歷的集合的介面
 *
 * @author jiangpingping
 * @date 2018/8/27 下午9:31
 */
public interface Aggregate<E> {

    /**
     * 返回當前集合的迭代器
     *
     * @return 當前集合的迭代器
     */
    Iterator<E> iterator();

}

該介面遵循類圖的設計,介面中包含建立Iterator介面實現類物件的方法。

  • 迭代器介面Iterator
package cn.itlemon.design.pattern.chapter01.iterator.example;

/**
 * 迭代器介面
 *
 * @author jiangpingping
 * @date 2018/8/27 下午9:32
 */
public interface Iterator<E> {

    /**
     * 檢測是否有下一個元素
     *
     * @return 如果有,返回true,否則返回false
     */
    boolean hasNext();

    /**
     * 返回當前元素,並將指標指向下一個元素
     *
     * @return 當前元素
     */
    E next();

}

該迭代器介面有兩個方法,分別是判斷被遍歷的集合是否還有元素以及獲取集合中元素並將指標指向下一個元素。

  • 具體的集合類BookShelf
package cn.itlemon.design.pattern.chapter01.iterator.example;

import java.util.ArrayList;

/**
 * 書架,其實就是承載書籍的集合或陣列
 *
 * @author jiangpingping
 * @date 2018/8/27 下午9:42
 */
public class BookShelf<E> implements Aggregate {

    private ArrayList<E> books;

    private int last = 0;

    public BookShelf(int initSize) {
        books = new ArrayList<>(initSize);
    }

    public E getBookAt(int index) {
        return books.get(index);
    }

    public void appendBook(E e) {
        books.add(e);
        last++;
    }

    public int getLength() {
        return last;
    }

    @Override
    public Iterator<E> iterator() {
        return new BookShelfIterator<>(this);
    }
}

getBookAt方法可以獲取指定索引位置的書籍,appendBook方法是向書架中最後一個位置新增書籍的方法,getLength方法可以得到書籍的數量,iterator方法可以獲取當前書架的迭代器實現類物件。

  • 迭代器實現類BookShelfIterator
package cn.itlemon.design.pattern.chapter01.iterator.example;

/**
 * {@link BookShelf} 的迭代器
 *
 * @author jiangpingping
 * @date 2018/8/27 下午9:49
 */
public class BookShelfIterator<E> implements Iterator<E> {

    private BookShelf<E> bookShelf;

    private int index;

    public BookShelfIterator(BookShelf<E> bookShelf) {
        this.bookShelf = bookShelf;
        index = 0;
    }

    @Override
    public boolean hasNext() {
        return index < bookShelf.getLength();
    }

    @Override
    public E next() {
        E e = bookShelf.getBookAt(index);
        index++;
        return e;
    }
}

hasNext方法可以判斷遍歷的集合中是否還有未遍歷的元素,next方法直接獲取元素,並將在指標指向下一個元素,所以在使用List的迭代器的時候,要特別留意next方法,在每次迴圈的過程中,next方法只能使用一次,多次使用的話,單次遍歷會引起邏輯錯誤。

  • 書籍類Book
package cn.itlemon.design.pattern.chapter01.iterator.example;

/**
 * 書籍的實體類
 *
 * @author jiangpingping
 * @date 2018/8/27 下午9:39
 */
public class Book {

    private String name;

    public Book(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

}
  • 測試類Main
package cn.itlemon.design.pattern.chapter01.iterator.example;

/**
 * 測試Iterator模式的主類
 *
 * @author jiangpingping
 * @date 2018/8/27 下午10:01
 */
public class Main {

    public static void main(String[] args) {
        BookShelf<Book> bookShelf = new BookShelf<>(4);
        bookShelf.appendBook(new Book("深入理解Java虛擬機器"));
        bookShelf.appendBook(new Book("深入分析Java Web技術內幕"));
        bookShelf.appendBook(new Book("Java程式設計思想"));
        bookShelf.appendBook(new Book("Linux就該這麼學"));
        Iterator<Book> iterator = bookShelf.iterator();
        while (iterator.hasNext()) {
            Book book = iterator.next();
            System.out.println(book.getName());
        }
    }
}

看到上面的測試主類,和使用ArrayList的迭代器一模一樣,也就是說,我們手動實現了迭代器設計模式,其實,在設計過程中,所有的泛型都是使用E來進行代替的,所以這些類不僅僅適用Book的遍歷,支援其他類的遍歷,如果在將類的名稱修改一下,改成更加通用的,那麼這個迭代器就將適合更多的集合遍歷,遍歷的元素可以是其他的類物件。

淺析迭代器模式中的重要角色

任何模式都是前人積累下來的經驗,大多數模式中都有固定的角色,使用模式的時候,可以根據固定的角色來編寫程式碼,就可以輕鬆地利用上設計模式,使自己的程式碼更具有“可複用性”。接下來將淺析迭代器設計模式中的重要角色。

  • Iterator(迭代器介面)
    該角色負責定義按順序逐個遍歷元素的介面(API),在本次示例中,由Iterator介面扮演了這個角色,它定義了兩個方法,hasNextnext方法,分別是判斷被遍歷的集合或者陣列是否還有下一個元素以及直接獲取元素,並將指標指向下一個元素。

  • ConcreteIterator(具體的迭代器)
    該角色實現了Iterator所定義的介面(API),在本次示例中,由BookShelfIterator類來扮演了這個角色,它持有需要遍歷的陣列或者集合的具體資訊,也就是說需要被遍歷的集合存在於這個迭代器中。

  • Aggregate(集合)
    該角色負責定義建立Iterator角色的介面(API),這個介面會創建出一個Iterator的實現類物件,這個實現類物件可以對實現Aggregate集合介面類物件進行遍歷。本次示例中,由Aggregate介面來扮演這個角色。

  • ConcreteAggregate(具體的集合)
    該角色負責實現Aggregate所定義的介面(API),它會創建出具體的Iterator角色,也就是ConcreteIterator角色。在本次示例中,由BookShelf扮演了這個角色,它實現類iterator方法。

迭代器設計模式UML類圖

這裡寫圖片描述

為什麼要使用迭代器設計模式

為什麼在遍歷的時候要額外引入迭代器這種複雜的模式呢?

也許你有這樣的疑問,引入迭代器設計模式的一個重要理由是:將實現和遍歷進行了分離,也就是說遍歷的過程完全不依賴與你所選擇的集合是如何實現的,在示例中,使用的ArrayList來承載資料的,如果開發者換了其他的容器來承載資料,那麼只需要修改集合的實現方式即可,完全不需要去修改遍歷的過程程式碼,這就提高了程式碼的“可複用性”和“可靠性”。

相關推薦

設計模式01——Iterator模式

定義 迭代器(Iterator)模式,從其英文單詞可以看出,有反覆做某件事的意思。迭代器模式常用於資料集合中,對資料集合中的資料按照順序進行遍歷。它能提供一種方法訪問一個容器物件中各個元素,而又不暴露該物件的內部細節。 問題引入 假設我們有一個書架,假

圖解設計模式Iterator模式

strong ack [] 示例 AI pac method gre etl 一:什麽是Iterator模式? 將循環變量i的作用抽象化,通用化形成的模式,在設計模式中稱為Iterator模式(叠代器模式),該模式用於在數據集合中按照順序遍歷集合 二:為什麽要有Iterat

設計模式01-----策略模式

工具 div 天上 的區別 區分 inter nts ... 所有 我的理解,策略模式就是提供很多策略。比如,每天上班的交通工具,可以自行車,公交車,地鐵等等策略。而誰來使用這個策略呢,上班族。 下面特點摘自菜鳥教程:“ 意圖:定義一系列的算法,把它們一個個封

設計模式——01 策略模式

1 Strategy Pattern(策略模式) 1.1設計原則一          下面舉個例子說明這個原則。 1)案例分析一:       &nbs

單例模式及常見寫法分析(設計模式01

啟動 nes 成員變量 額外 log 序列 spa tar adl 保證一個類僅有一個實例。並提供一個該實例的全局訪問點。 ——《設計模式》單例模式的概念非常easy。以下以C#語言為樣例,列出常見單例寫法的優缺點。1、簡單實現 public s

設計模式-01

arr 觀察者 pack implement 會有 實例 new ring ride 1 接口設計模式   適用於:需要對一個類或一組類的方法進行定義或重定義的場景 package com.beifeng.hadoop.pattern.interfacee; /** *

【Unity與23種設計模式】叠代器模式Iterator

存儲對象 函數庫 叠代器 每一個 語言 不知道 集合體 程序設計 順序 GoF中定義: “在不知道集合內部細節的情況下,提供一個按序方法存取一個對象集合體的每一個單元。” 叠代器模式由於經常使用到 已經被現代程序設計語言納為標準語句或收錄到標準函數庫中 在C#中

C++設計模式01——簡單工廠模式

actor 異常 main turn mes .com factory format 創建過程 http://blog.csdn.net/caoshangpa/article/details/52763923 問題描述 之前在公司做了一個windows 8平臺的閱讀器。

GOF23設計模式之叠代器模式iterator

jdk gre reat ray ring return 示例代碼 開發 叠代器模式 一、叠代器模式概述   提供一種可以遍歷聚合對象的方式。又稱為:遊標(cursor)模式   結構:     (1)聚合對象:存儲數據     (2)叠代器:遍歷數據 二、叠代器模式示例代

01設計模式——單例模式

dsi 同步塊 .com 調優 博客 true 指令 反射 run 前言:以下總結來自龍哥---左瀟龍博客。 總結的很到位,附上博客鏈接:http://www.cnblogs.com/zuoxiaolong/p/pattern2.html 目的:盡可能的節約內存空間,減少無

設計模式一:叠代器(Iterator)模式

open 先來 strac alt rri print pre 並且 3-0 一、什麽是叠代器模式   說白了就是一種遍歷集合中元素的一種設計模式,我們趕緊先來看一下例子 二、實現舉例   這裏我們舉一個例子,是將書(Book)放置到書架中(BookShelf),一個叠

圖解設計模式-Iterator模式

[] align 類集 getname ole book lse pan interface 使用抽象類和接口,弱化類之間的耦合,使類可以更容易組件化 不使用具體類編程,要優先使用抽象類和接口編程 角色劃分: Iterator叠代器接口,定義遍歷元素的接口,hasNex

重走Java設計模式——迭代器模式Iterator Pattern)

迭代器模式 定義 提供一種方法順序訪問一個聚合物件中各個元素, 而又無須暴露該物件的內部表示。 模式結構 1.抽象容器:一般是一個介面,提供一個iterator()方法,例如java中的Collection介面,List介面,Set介面等。 2.具體

設計模式01 建立型模式 - 單例模式(Singleton Pattern)

參考 [1] 設計模式之:建立型設計模式(6種) | 部落格園 [2] 單例模式的八種寫法比較 | 部落格園   單例模式(Singleton  Pattern) 確保一個類有且僅有一個例項,並且為客戶提供一個全域性訪問點。   特點 1) 保證被訪問資

設計模式01-----builder設計模式

最近開發任務中碰到一個非常好用的模式,那就是builder設計模式(即建造者設計模式)。 說到builder設計模式,常常會跟可重疊構造器和javabeans模式一起比較說明。下面分別討論: 一. 可重疊構造器模式 可重疊構造器的意思就是有很多的構造器,只是引數個數,引數型別不一樣。舉個到處都在用的例子

01設計模式 -- 單例模式

 設計模式之單例模式   定義:單例模式主要作用是保證在Java應用程式中,一個類Class只有一個例項存在   單例模式為我們提供了這樣的實現。使用單例的好處還在於可以節省記憶體,因為它限制了例項的個數,有利於Java的垃圾回收(garbage collection)。   我們常常看到工廠模式中類載

(五)設計模式之迭代器模式Iterator

前言: 參考圖書:軟體設計模式與體系結構 參考部落格:https://www.cnblogs.com/wanson/articles/9277813.html   正題:         迭代器(iterator)有時又稱遊標

C#設計模式01-工廠方法模式(附原始碼)

     在簡單工廠模式中,工廠類負責建立所有產品的例項,這導致工廠類的職責太重,並且一旦工廠類無法正常工作,整個系統將會受到極大的影響,而且簡單工廠模式並不能很好的符合開閉原則。為了解決簡單工廠模式的這些缺點,工廠方法模式誕生了。  &nb

[設計模式] - No.4 Iterator 模式

Iterator 模式 本系列的文章主要是記錄設計模式的學習過程,圍繞《圖解設計模式》和我自身對於設計模式的理解。在文章中出現的程式碼多為《圖解設計模式》這本書中的程式碼。書中一共包含23個設計模式,這篇文章作為這個系列的第一篇文章。由於《圖解設計模式》這本書內容十分簡單,非常適合入

設計模式——迭代器(Iterator)模式

  概述   迭代器模式簡單的說(按我目前的理解)就是一個類提供一個對外迭代的介面,方面呼叫者迭代。這個迭代介面至少包括兩個方法:hasNext()--用於判斷是否還有下一個,next()--用於取出下一個物件(或值)。而外部使用這個類(取出這個類中的物件或值)時,不用關心這個類儲存物