1. 程式人生 > 實用技巧 >【設計模式】迭代器模式

【設計模式】迭代器模式

迭代器模式

簡介

通過引入迭代器,可以將資料的遍歷功能從聚合物件中分離出來,這樣一來,聚合物件只需負責儲存資料,而迭代器物件負責遍歷資料,使得聚合物件的職責更加單一,符合單一職責原則

迭代器模式:提供一種方法順序訪問一個聚合物件中的各個元素,而又不暴露該物件的內部表示。

結構

實現

實現方式:

  • 宣告迭代器介面。該介面必須提供至少一個方法來獲取集合中的下個元素。但為了使用方便,還可以新增一些其他方法,例如獲取前一個元素、記錄當前位置和判斷迭代是否已經結束。
  • 宣告集合介面並描述一個獲取迭代器的方法。其返回值必須是迭代器介面。如果計劃擁有多組不同的迭代器,則可以宣告多個類似的方法。
  • 為希望使用迭代器進行遍歷的集合實現具體迭代器類。迭代器物件必須與單個集合實體連結。連結關係通常通過迭代器的建構函式建立。
  • 在集合類中實現集合介面。其主要思想是針對特定集合為客戶端程式碼提供建立迭代器的快捷方式。集合物件必須將自身傳遞給迭代器的建構函式來建立兩者之間的連結。
  • 檢查客戶端程式碼,使用迭代器替代所有集合遍歷程式碼。每當客戶端需要遍歷集合元素時都會獲取一個新的迭代器。
#include <iostream>
#include <string>
#include <vector>

template <typename T, typename U>
class Iterator {
public:
    typedef typename std::vector<T>::iterator iter_type;
    Iterator(U *p_data, bool reverse = false) : m_p_data_(p_data), m_it_(m_p_data_->m_data_.begin()) {}
    void first() {
        m_it_ = m_p_data_->m_data_.begin();
    }
    void next() {
        m_it_++;
    }
    bool isDone() {
        return (m_it_ == m_p_data_->m_data_.end());
    }
    iter_type Current() {
        return m_it_;
    }

private:
    U *m_p_data_;
    iter_type m_it_;
};

template <class T>
class Container {
    friend class Iterator<T, Container>;

private:
    std::vector<T> m_data_;

public:
    void add(T a) {
        m_data_.push_back(a);
    }
    Iterator<T, Container> *CreateIterator() {
        return new Iterator<T, Container>(this);
    }
};

class CustomData {
private:
    int m_data_;

public:
    CustomData(int a = 0) : m_data_(a) {}
    void setData(int a) {
        m_data_ = a;
    }
    int data() const { 
        return m_data_;
    }
};

void ClientCode() {
    std::cout << "Iterator with int:\n";
    Container<int> cont;
    for(int i = 0; i < 10; ++i) {
        cont.add(i);
    }

    Iterator<int, Container<int>> *it = cont.CreateIterator();
    for(it->first(); !it->isDone(); it->next()) {
        std::cout << *it->Current() << std::endl;
    }

    std::cout << "\n";

    std::cout << "Iterator with custom Class:\n";
    Container<CustomData> cont2;
    CustomData a(100), b(1000), c(10000);
    cont2.add(a);
    cont2.add(b);
    cont2.add(c);
    Iterator<CustomData, Container<CustomData>> *it2 = cont2.CreateIterator();
    for(it2->first(); !it2->isDone(); it2->next()) {
        std::cout << it2->Current()->data() << std::endl;
    }

    delete it;
    delete it2;
}

int main(int argc, char *argv[]) {
    ClientCode();

    return 0;
}
from __future__ import annotations
from collections.abc import Iterator, Iterable
from typing import Any, List


class AlphabeticalOrderIterator(Iterator):
    """
    """
    _position: int = None
    _reverse: bool = False

    def __init__(self, collection: WordsCollection, reverse: bool = False) -> None:
        self._collection = collection
        self._reverse = reverse
        self._position = -1 if reverse else 0

    def __next__(self):
        try:
            value = self._collection[self._position]
            self._position += -1 if self._reverse else 1
        except IndexError:
            raise StopIteration()

        return value


class WordsCollection(Iterable):
    """
    """
    def __init__(self, collection: List[Any] = []) -> None:
        self._collection = collection

    def __iter__(self) ->AlphabeticalOrderIterator:
        return AlphabeticalOrderIterator(self._collection)

    def get_reverse_iterator(self) -> AlphabeticalOrderIterator:
        return AlphabeticalOrderIterator(self._collection, True)

    def add_item(self, item: Any):
        self._collection.append(item)


if __name__ == "__main__":
    collection = WordsCollection()
    collection.add_item("First")
    collection.add_item("Second")
    collection.add_item("Third")

    print("Straight traversal:")
    print("\n".join(collection))
    print("")

    print("Reverse traversal:")
    print("\n".join(collection.get_reverse_iterator()), end="")

例項

問題描述

模擬遙控器操作電視訊道的過程。

問題解答

// Example.cpp


總結

優點

  • 單一職責原則。通過將體積龐大的遍歷演算法程式碼抽取為獨立的類,可對客戶端程式碼和集合進行整理。
  • 開閉原則。可實現新型的集合和迭代器並將其傳遞給現有程式碼,無需修改現有程式碼。
  • 可以並行遍歷同一集合,因為每個迭代器物件都包含其自身的遍歷狀態。
  • 相似的,可以暫停遍歷並在需要時繼續。

缺點

  • 如果程式只與簡單的集合進行互動,應用該模式可能會矯枉過正。
  • 對於某些特殊集合,使用迭代器可能比直接遍歷的效率低。

場景

  • 當集合背後為複雜的資料結構,且希望對客戶端隱藏其複雜性時(出於使用便利性或安全性的考慮),可以使用迭代器模式。
  • 使用該模式可以減少程式中重複的遍歷程式碼。
  • 希望程式碼能夠遍歷不同的甚至是無法預知的資料結構,可以使用迭代器模式。

與其他模式的關係

  • 可以使用迭代器模式來遍歷組合模式樹。
  • 可以同時使用工廠方法模式迭代器模式來讓子類集合返回不同型別的迭代器,並使得迭代器與集合相匹配。
  • 可以同時使用備忘錄模式迭代器模式來獲取當前迭代器的狀態,並在需要的時候進行回滾。
  • 可以同時使用訪問者模式迭代器模式來遍歷複雜資料結構,並對其中的元素執行所需操作,即使這些元素所屬的類完全不同。