迭代器模式


2021年11月27日18:24:29

迭代器模式

定義

Provide a way to access the elements of an aggregate object sequentially without
exposing its underlying representation. ——《Design Patterns: Elements of Reusable Object-Oriented Software》

提供一種順序訪問集合的元素而不暴露其底層表示的方法。 ——《設計模式:可復用面向對象軟件的基礎》

迭代器模式是一種行為型模式。

明明講

迭代器模式就是提供一種遍歷的方法,這種方法有兩個特點:一是按你想要的方式訪問到你想訪問的元素,二是不暴露底層是什么存的,怎么存的。

在開發過程中,我們使用類庫提供給我們的集合,遍歷集合中的元素,使用的就是迭代器。一般情況下,單單作為使用者,我們是不會去關注這些集合底層結構是什么,只需要拿到我們需要的數據,進行業務邏輯的處理就可以了。但是呢,作為一個優秀的開發者,當然要深入了解各種集合的數據結構及操作的。當然啦,我們是不會說我們是為了面試才去了解的啦。(此處應該有表情)

常見用法:

    List<String> list = new ArrayList<>();
    list.add("ming");
    list.add("ming");
    list.add("come");
    for(String s : list) {
        System.out.println(s);
    }

上面代碼中的for循環遍歷列表中的數據,Java編譯器會將這段代碼變成使用ArrayList中的迭代器去遍歷數據。編譯之后再反編譯,代碼如下:

    List<String> list = new ArrayList();
    list.add("ming");
    list.add("ming");
    list.add("come");
    Iterator var1 = list.iterator();

    while(var1.hasNext()) {
        String s = (String)var1.next();
        System.out.println(s);
    }

圖示

迭代器模式結構圖:

迭代器模式結構圖

角色

抽象迭代器角色(Iterator):

  • 定義一個接口,用於訪問和遍歷元素,它的方法一般有:first、next、hasNext等。

具體迭代器角色(ConcreteIterator):

  • 實現【抽象迭代器角色】定義的執行操作
  • 記錄集合迭代時的當前位置,如圖中的currentItem()方法
  • 當客戶端控制迭代,迭代器被稱作外部迭代器;當迭代器控制迭代,迭代器是內部迭代器。(When the client controls the iteration, the iterator is called an external
    iterator, and when the iterator controls it, the iterator is aninternal iterator.)
  • Java類庫中AbstractList、ArrayList、HashMap中都有具體迭代器

抽象集合角色(Aggregate):

  • 定義了一個接口,用於創建迭代器對象

具體集合角色(ConcreteAggregate):

  • 實現【抽象集合角色】,實現創建迭代器對象方法,返回一個迭代器實例

代碼示例

家有小女,名為曉月,一歲有余,嚶嚶學語。

除夕佳節,給家人拜年,爺爺奶奶,爸爸媽媽,叔叔嬸嬸,還有曉月自己,新年快樂。

類圖:

代碼示例類圖

抽象迭代器角色:
public interface NameIterator {
    String next();
    boolean hastNext();
}
抽象集合角色:
public interface FamilyAggregate {
    NameIterator createIterator();
    boolean addFamily(int generation, String name);
}

具體集合角色和具體迭代器角色:
// 具體集合類
public class FamilyAggregateImpl implements FamilyAggregate {

    private int generation;

    private List<String>[] generations;

    public FamilyAggregateImpl(int generation) {
        this.generation = generation;
        this.generations = initFamily(generation);
    }

    private List<String>[] initFamily(int generation) {
        List<String>[] name = new ArrayList[generation];
        for (int i = 0; i < generation; i++) {
            name[i] = new ArrayList<>();
        }
        return name;
    }

    public boolean addFamily(int generation, String name) {
        return generations[generation - 1].add(name);
    }

    @Override
    public NameIterator createIterator() {
        return new NameIteratorImpl();
    }

    // 具體迭代器
    private class NameIteratorImpl implements NameIterator {

        int currentGeneration;

        int cursor;

        NameIteratorImpl() {
            this.currentGeneration = FamilyAggregateImpl.this.generation;
        }

        @Override
        public String next() {
            int i = cursor;
            List<String>[] generations = FamilyAggregateImpl.this.generations;
            if (currentGeneration == 1 && cursor == generations.length) {
                System.out.println("無剩余可遍歷");
            }
            String name = generations[currentGeneration - 1].get(i);
            cursor = i + 1;
            if (cursor == generations[currentGeneration - 1].size()) {
                currentGeneration--;
                cursor = 0;
            }
            return name;
        }

        @Override
        public boolean hastNext() {
            return currentGeneration != 0;
        }
    }

}
客戶端
public class Client {
    public static void main(String[] args) {
        FamilyAggregate family = new FamilyAggregateImpl(3);

        family.addFamily(1, "曉月");
        family.addFamily(2, "爸爸");
        family.addFamily(2, "媽媽");
        family.addFamily(2, "叔叔");
        family.addFamily(2, "嬸嬸");
        family.addFamily(3, "爺爺");
        family.addFamily(3, "奶奶 ");

        NameIterator iterator = family.createIterator();
        while (iterator.hastNext()) {
            String name = iterator.next();
            System.out.println(name);
        }

    }
}

結果如下:

爺爺
奶奶 
爸爸
媽媽
叔叔
嬸嬸
曉月

使用場景

  • 1、訪問一個聚合對象的內容而無須暴露它的內部表示。
  • 2、可以為聚合對象提供多種遍歷方式,比如順序、逆序等。
  • 3、為遍歷不同的聚合結構提供一個統一的接口,比如訪問下一個元素的方法是next。

優點

  • 1、它支持以不同的方式遍歷一個聚合對象。
  • 2、迭代器簡化了聚合類。
  • 3、在同一個聚合上可以有多個遍歷。
  • 4、在迭代器模式中,增加新的聚合類和迭代器類都很方便,無須修改原有代碼。

缺點

  • 由於迭代器模式將存儲數據和遍歷數據的職責分離,增加新的聚合類需要對應增加新的迭代器類,類的個數成對增加,這在一定程度上增加了系統的復雜性。

總結

迭代器模式應該是最常見的設計模式了,可以說Java程序員只要開發,都要使用它。

迭代器模式是一種行為型設計模式,它為集合提供了一個遍歷元素的方式,又不會暴露它的內部表示。

2021年12月7日01:47:38


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM