设计模式 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.总结
迭代器模式是一种非常实用的设计模式,它可以帮助我们简化对集合的遍历操作,并提高代码的可读性和可维护性。在使用迭代器模式时,遵循以上经验可以帮助我们写出更加健壮和高效的代码。
7.行为模式汇总图




















