設計模式 18 迭代器模式 Iterator Pattern
1.定義
迭代器模式 (Iterator Pattern) 是一種行為型設計模式,它提供了一種訪問集合元素的標準方法,而無需暴露集合的內部表示。
提供一種方法順序訪問一個聚合對象中的各個元素,而又不需要暴露該對象的內部表示。
核心思想來自將遍歷集合的邏輯從集合本身中分離出來,封裝到一個獨立的迭代器對象中。
迭代器對象負責維護遍歷的當前位置,并提供訪問下一個元素的方法。
想象一個書架,上面擺滿了書籍。如果你想閱讀這些書籍,你可以選擇不同的方式:
- 直接訪問: 你直接走到書架前,從最左邊開始一本一本地拿書閱讀。
- 使用書簽: 你用書簽標記當前閱讀的位置,下次閱讀時直接從書簽處開始。
2.內涵
迭代器模式就像使用書簽一樣,它提供了一種間接訪問集合元素的方式:
迭代器對象: 就像書簽,它記錄了當前訪問的位置。
- next() 方法: 就像翻到下一頁,它返回下一個元素。
- hasNext() 方法: 就像判斷是否有下一頁,它判斷是否還有下一個元素。
3.案例分析
/Iterator Design Pattern/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>;public:void Add(T a) {m_data_.push_back(a);}Iterator<T, Container> CreateIterator() {return new Iterator<T, Container>(this);}private:std::vector<T> m_data_;
};class Data {public:Data(int a = 0) : m_data_(a) {}void set_data(int a) {m_data_ = a;}int data() {return m_data_;}private:int m_data_;
};void ClientCode() {std::cout << "________________Iterator with int______________________________________" << std::endl;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;}Container<Data> cont2;Data a(100), b(1000), c(10000);cont2.Add(a);cont2.Add(b);cont2.Add(c);std::cout << "________________Iterator with custom Class______________________________" << std::endl;Iterator<Data, Container<Data>> it2 = cont2.CreateIterator();for (it2->First(); !it2->IsDone(); it2->Next()) {std::cout << it2->Current()->data() << std::endl;}delete it;delete it2;
}int main() {ClientCode();return 0;
}
上述代碼 uml 類圖如下
4.注意事項
?? ? 迭代器模式 Iterator Pattern 使用時需要注意什么?
?? ?使用迭代器模式時,需要注意以下幾點:
?? ?1. 迭代器狀態的維護:
?? ? 迭代器對象需要維護當前遍歷的位置,確保每次調用 `next()` 方法都能返回下一個元素。
?? ? 迭代器對象需要處理遍歷結束的情況,例如在 `hasNext()` 方法中返回 `false`,或在 `next()` 方法中拋出異常。
?? ?2. 迭代器的類型:
?? ? 迭代器可以是內部迭代器,也稱為迭代器方法,它將遍歷邏輯封裝在集合類內部,例如 Java 中的 `forEach` 方法。
?? ? 迭代器可以是外部迭代器,它是一個獨立的類,負責遍歷集合,例如 Java 中的 `Iterator` 接口。
?? ?3. 迭代器的可復用性:
?? ? 迭代器對象通常是不可復用的,因為它們維護了遍歷狀態。
?? ? 如果需要多次遍歷同一個集合,需要創建新的迭代器對象。
?? ?4. 迭代器的并發訪問:
?? ? 如果多個線程同時訪問同一個迭代器對象,可能會導致數據不一致或異常。
?? ? 在并發環境中使用迭代器時,需要進行同步處理,例如使用鎖機制來保護迭代器對象。
?? ?5. 迭代器的性能:
?? ? 迭代器的性能取決于集合的類型和迭代器的實現方式。
?? ? 對于一些集合類型,例如鏈表,迭代器可能比直接訪問元素效率低。
?? ?6. 迭代器的靈活性:
?? ? 迭代器模式可以提供靈活的遍歷方式,例如正序、逆序、隨機訪問等。
?? ? 可以根據需要自定義迭代器,實現不同的遍歷邏輯。
?? ?總結:
?? ?迭代器模式是一種強大的設計模式,它可以簡化對集合的遍歷操作,并提供靈活的遍歷方式。在使用迭代器模式時,需要關注迭代器狀態的維護、類型、可復用性、并發訪問和性能等方面,以確保代碼的正確性和效率。
5.最佳實踐
在使用迭代器模式時,除了前面提到的需要注意的地方,還需要遵循以下經驗:
1. 明確迭代器職責
迭代器應該只負責遍歷集合,不應該包含其他操作,例如修改集合元素。
如果需要修改集合元素,應該使用專門的方法,而不是通過迭代器來實現。
2. 保持迭代器簡單
迭代器應該盡可能簡單易懂,避免過度設計。
迭代器應該只包含必要的操作,例如 hasNext()、next() 等。
3. 考慮迭代器的性能
如果需要頻繁遍歷集合,應該選擇性能較高的迭代器實現。
對于一些特殊類型的集合,例如鏈表,可能需要使用自定義迭代器來提高性能。
4. 避免迭代器中的副作用
迭代器不應該修改集合的狀態,例如添加或刪除元素。
如果需要修改集合,應該使用專門的方法,而不是通過迭代器來實現。
5. 使用迭代器模式的最佳實踐
優先使用語言提供的內置迭代器,例如 Java 中的 Iterator 接口。
如果需要自定義迭代器,應該遵循迭代器模式的規范,并提供必要的操作。
避免在迭代器中使用 break 或 continue 語句,因為它們會破壞迭代器的正常邏輯。
6. 迭代器與并發
在并發環境中使用迭代器時,需要格外小心,因為多個線程可能會同時訪問同一個迭代器對象。
如果需要在并發環境中使用迭代器,應該使用線程安全的迭代器實現,例如 Java 中的 ConcurrentIterator 接口。
6.總結
????????迭代器模式是一種非常實用的設計模式,它可以幫助我們簡化對集合的遍歷操作,并提高代碼的可讀性和可維護性。在使用迭代器模式時,遵循以上經驗可以幫助我們寫出更加健壯和高效的代碼。