国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

設(shè)計模式學(xué)習(xí)筆記 - 設(shè)計模式與范式 -行為型:9.迭代器模式(上):相比直接遍歷集合數(shù)據(jù),使用迭代器模式有哪些優(yōu)勢?

這篇具有很好參考價值的文章主要介紹了設(shè)計模式學(xué)習(xí)筆記 - 設(shè)計模式與范式 -行為型:9.迭代器模式(上):相比直接遍歷集合數(shù)據(jù),使用迭代器模式有哪些優(yōu)勢?。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

概述

上篇文章,我們學(xué)習(xí)了狀態(tài)模式。狀態(tài)模式是狀態(tài)機的一種實現(xiàn)方式。它通過將事件觸發(fā)的狀態(tài)轉(zhuǎn)移和動作執(zhí)行,拆分到不同的狀態(tài)類中,以此來避免狀態(tài)機類中的分支判斷邏輯,應(yīng)對狀態(tài)機類代碼的復(fù)雜性。

本章,學(xué)習(xí)另外一種行為型設(shè)計模式,迭代器模式。它用來遍歷集合對象。不過,很多編程語言都將迭代器作為一個基礎(chǔ)的類庫,直接提供出來了。在平時的開發(fā)中,特別是業(yè)務(wù)開發(fā),直接使用即可,很少會自己去實現(xiàn)一個迭代器。不過,知其然知其所以然,弄懂原理能幫助我們更好的使用這些工具類,所以,還是有必要學(xué)習(xí)一下這個模式。

我們知道,大部分編程語言都提供了多種遍歷集合的方式,比如 for 循環(huán)、foreach 循環(huán)、迭代器等。所以,本章除了講解迭代器的原理和實現(xiàn)之外,還會重點說一下,相對于其他的遍歷方式,利用迭代器來遍歷集合的優(yōu)勢。


迭代器模式的實現(xiàn)原理

迭代器模式(Iterator Design Pattern),也叫作游標(biāo)模式(Cusor Design Pattern)。

它用來遍歷集合對象。這里說的 “集合對象” 也叫做 “容器” “聚合對象”,實際上就是包含一組對象的對象,比如數(shù)組、鏈表、樹、圖、跳表。迭代器將集合對象的遍歷操作從集合類中拆分出來,放到迭代器類中,讓兩者的職責(zé)更加單一。

迭代器是用來遍歷容器的,所以,一個完整的迭代器模式一般會涉及到容器容器迭代器兩部分內(nèi)容。為了達到基于接口而非實現(xiàn)編程的目的,容器包含容器接口、容器實現(xiàn)類,迭代器包含迭代器接口、迭代器實現(xiàn)類。對于迭代器模式,我繪制了一張簡單的類圖。
設(shè)計模式學(xué)習(xí)筆記 - 設(shè)計模式與范式 -行為型:9.迭代器模式(上):相比直接遍歷集合數(shù)據(jù),使用迭代器模式有哪些優(yōu)勢?,設(shè)計模式-實戰(zhàn),迭代器模式
接下來通過一個例子,來講解如何實現(xiàn)一個迭代器。

概述中提到過,大部分編程語言都提供了遍歷容器的迭代器類,在平時開發(fā)中,直接拿來使用即可,幾乎不大可能從零去編寫一個迭代器。不過,這里為了講解迭代器的實現(xiàn)原理,我們假設(shè)某個新的編程語言的基礎(chǔ)類庫中,還沒有提供線性容器對應(yīng)地迭代器,需要從零開始開發(fā)。

線性數(shù)據(jù)結(jié)構(gòu)包括鏈表和數(shù)組,在大部分編程語言中都有對應(yīng)地類來封裝這兩種數(shù)據(jù)結(jié)構(gòu),在開發(fā)中直接拿來使用就可以了。假設(shè)在新的編程語言中,這兩個數(shù)據(jù)結(jié)分別對應(yīng) ArrayListLinkedList 兩個類。此外,我們從兩個類中抽象出公共的接口,定義為 List 接口,以方便開發(fā)者基于接口而非實現(xiàn)編程。

現(xiàn)在,針對 ArrayListLinkedList 兩個線性容器,設(shè)計實現(xiàn)對應(yīng)的迭代器。按照之前給出的迭代器類圖,先定義一個接口 Iterator 以及針對這兩種容器的迭代器實現(xiàn)類 ArrayIteratorLinkedIterator

先看下 Iterator 接口的定義。具體代碼如下所示:

// 接口定義方式一
public interface Iterator<E> {
    boolean hasNext();
    void next();
    E currentItem();
}

// 接口定義方式二
public interface Iterator<E> {
    boolean hasNext();
    E next();
}

Iterator 接口有兩種定義方式。

  • 在第一種定義中, next() 函數(shù)用來將游標(biāo)后移一位元素,currentItem() 函數(shù)用來返回當(dāng)前游標(biāo)執(zhí)行的元素。
  • 在第二種定義中,返回當(dāng)前元素與后移一位這兩個操作,都要放到同一個函數(shù) next() 中完成。

第一種實現(xiàn)方式更加靈活些,比如可以多次調(diào)用 currentItem() 查詢當(dāng)前元素,而不移動游標(biāo)。所以,在接下來的實現(xiàn)中,我們選擇第一種接口定義方式。

現(xiàn)在,我們再來看一下 ArrayIterator 的代碼實現(xiàn),具體如下所示。代碼實現(xiàn)非常簡單,不需要太多解釋。

public class ArrayIterator<E> implements Iterator<E> {
    private int cursor;
    private ArrayList<E> arrayList;

    public ArrayIterator(ArrayList<E> arrayList) {
        this.cursor = 0;
        this.arrayList = arrayList;
    }

    @Override
    public boolean hasNext() {
        return cursor != arrayList.size(); // 注意這里,cursor在指向最后一個元素的時候,hasNext()仍返回true
    }

    @Override
    public void next() {
        cursor++;
    }

    @Override
    public E currentItem() {
        if (cursor >= arrayList.size()) {
            throw new NoSuchElementException();
        }
        return arrayList.get(cursor);
    }
}

public class Demo {
    public static void main(String[] args) {
        ArrayList<String> names = new ArrayList<>();
        names.add("chen");
        names.add("jian");
        names.add("seng");

        Iterator<String> iterator = new ArrayIterator<>(names);
        while (iterator.hasNext()) {
            System.out.println(iterator.currentItem());
            iterator.next();
        }
    }
}

在上面的視線中,需要將待遍歷的容器對象,通過構(gòu)造函數(shù)傳遞給迭代器類。實際上,為了封裝迭代器的創(chuàng)建細節(jié),我們可以在容器中定義一個迭代器的 iterator() 方法,來創(chuàng)建對應(yīng)的迭代器。為了能基于接口而非實現(xiàn)編程,還需要將這個方法定義在 List 接口中。具體的代碼實現(xiàn)和使用如下所示。

public interface List<E> {
    Iterator iterator();
    // 省略其他接口函數(shù)...
}

public class ArrayList<E> implements List<E> {
    // ...
    @Override
    public Iterator iterator() {
        return new ArrayIterator(this);
    }
    // 省略其他代碼...
}

public class Demo {
    public static void main(String[] args) {
        ArrayList<String> names = new ArrayList<>();
        names.add("chen");
        names.add("jian");
        names.add("seng");

        Iterator<String> iterator = names.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.currentItem());
            iterator.next();
        }
    }
}

對于 LinkedIterator,它結(jié)構(gòu)和 ArrayIterator 完全相同,這里就不給出代碼了。

結(jié)合剛剛的例子,來總結(jié)一下迭代器設(shè)計思路。

  • 迭代器需要定義 hasNext()currentItem()、next() 三個最基本的方法。
  • 待遍歷的容器對象通過依賴注入傳遞到迭代器類中。
  • 容器通過 iterator() 方法來創(chuàng)建迭代器。

下面畫了一張類圖,你可以結(jié)合著看一看。

設(shè)計模式學(xué)習(xí)筆記 - 設(shè)計模式與范式 -行為型:9.迭代器模式(上):相比直接遍歷集合數(shù)據(jù),使用迭代器模式有哪些優(yōu)勢?,設(shè)計模式-實戰(zhàn),迭代器模式

迭代器模式的優(yōu)勢

迭代器的原理和實現(xiàn)講完了,現(xiàn)在,一起來看一下,使用迭代器遍歷集合的優(yōu)勢。

一般來講,遍歷集合數(shù)據(jù)有三種方法:for 循環(huán)、foreach 循環(huán)、iterator 迭代器。對照這三種方式,舉例說明下:

List<String> names = new ArrayList<>();
names.add("chen");
names.add("jian");
names.add("seng");

// 第一種遍歷方式,for循環(huán)
for (int i = 0; i < names.size(); i++) {
    System.out.print(names.get(i) + ",");
}

// 第二種遍歷方式,foreach循環(huán)
for (String name : names) {
    System.out.print(name + ",");
}

// 第三種遍歷方式,迭代器遍歷
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next() + ","); // Java 中的迭代器接口是第二種定義方式,next()即移動游標(biāo)又返回數(shù)據(jù)
}

實際上 foreach 循環(huán)只是一個語法糖而已,底層是基于迭代器來實現(xiàn)的。也就是說,上面的代碼中的第二種遍歷方式(foreach 循環(huán))的底層實現(xiàn),就是第三種遍歷方式(迭代器遍歷)。

從上面的代碼來看,for 循環(huán)遍歷方式比起迭代器遍歷方式,代碼看起來更加簡潔。那為什么還要用迭代器來遍歷容器呢?為什么還要給容器設(shè)計對應(yīng)的迭代器呢?原因有三個。

  • 首先,對于數(shù)組和鏈表這樣的數(shù)據(jù)結(jié)構(gòu),遍歷方式比較簡單,直接使用 for 循環(huán)來遍歷就足夠了。但是,對于復(fù)雜的數(shù)據(jù)結(jié)構(gòu)(比如樹、圖),有各種復(fù)雜的遍歷方式。比如,樹有前中后序、按層遍歷,圖有深度優(yōu)先、廣度優(yōu)先遍歷等等。如果由客戶端來實現(xiàn)這些遍歷算法,勢必增加開發(fā)成本,而且容易寫錯。如果將這部分遍歷的邏輯寫到容器類中,也會導(dǎo)致容器類代碼的復(fù)雜性。

    前面講過,應(yīng)對復(fù)雜性的方法就是拆分。可以將遍歷操作拆分到迭代器類中。比如,針對圖的遍歷,可以定義 DFSIterator、BFSIterator 兩個迭代器類,讓它們分別來實現(xiàn)深度優(yōu)先和廣度優(yōu)先遍歷。

  • 其次,將游標(biāo)指向的當(dāng)前位置等信息,存儲在迭代器類中,每個迭代器獨享游標(biāo)信息。這樣,我們就可以創(chuàng)建多個不同的迭代器類,同時對同一個容器進行遍歷而互不影響。

  • 最后,容器和迭代器提供了抽象接口,方便在開發(fā)時,基于接口而非實現(xiàn)編程。當(dāng)需要切換新的遍歷算法時,比如,從前往后遍歷鏈表切換成從后往前遍歷鏈表,客戶端只要將迭代器類從 LinkedIterator 切換為 ReversedLinkedIterator 即可,其他代碼不需要修改。此外添加新的遍歷算法,只需要擴展新的迭代器類,也更符合開閉原則。

總結(jié)

迭代器模式,也叫游標(biāo)模式。它用來遍歷集合對象。

這里說的 “集合對象”,也叫做 “容器” “聚合對象”,實際上就是包含一組對象的對象,比如數(shù)組、鏈表、樹、圖、跳表。

一個完整的迭代器模式,會設(shè)計容器和容器迭代器兩部分。為了達到基于接口而非實現(xiàn)編程的目的,容器又包含容器接口、容器實現(xiàn)類,迭代器又包含迭代器接口和迭代器實現(xiàn)類。容器中需要定義 iterator() 方法,用來創(chuàng)建迭代器。迭代器接口中需要定義 hasNext()、next()、currentItem() 三個最基本的方法。容器對象通過依賴注入傳遞到迭代器類中。

遍歷集合一般有 3 種方式:for 循環(huán)、foreach 循環(huán)、iterator 迭代器。后兩種本質(zhì)上屬于一種,都可以看做迭代器遍歷。相對于 for 循環(huán),利用迭代器遍歷有下面 3 個優(yōu)勢:文章來源地址http://www.zghlxwxcb.cn/news/detail-851609.html

  • 迭代器模式封裝集合內(nèi)部的復(fù)雜數(shù)據(jù)結(jié)構(gòu),開發(fā)者不需要了解如何遍歷,直接使用容器提供的迭代器即可。
  • 迭代器模式將集合對象的遍歷操作從集合類中拆分出來,放到迭代器類中,讓兩者的職責(zé)更加單一。
  • 迭代器模式讓添加新的遍歷算法更加容易,更符合開閉原則。此外,因為迭代器都實現(xiàn)自相同的接口,在開發(fā)中,基于接口而非實現(xiàn)編程,替換迭代器也變得更加容易。

到了這里,關(guān)于設(shè)計模式學(xué)習(xí)筆記 - 設(shè)計模式與范式 -行為型:9.迭代器模式(上):相比直接遍歷集合數(shù)據(jù),使用迭代器模式有哪些優(yōu)勢?的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包