当前位置: 首页 > news >正文

设计模式 18 迭代器模式 Iterator Pattern


设计模式 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.行为模式汇总图

相关文章:

  • 【QT八股文】系列之篇章2 | QT的信号与槽机制及通讯流程
  • vb.net,C#强制结束进程,“优雅”的退出方式
  • MyBatisPlus学习笔记(二)
  • 【STL】C++ stack(栈) 基本使用
  • 你真的会使用Vue3的onMounted钩子函数吗?Vue3中onMounted的用法详解
  • Wpf 使用 Prism 实战开发Day28
  • 第三方软件测试机构进行验收测试的好处分享,需多少时间和费用?
  • python -【一】基础语法
  • 计算机字符编码的发展
  • 机器学习(五) -- 监督学习(4) -- 集成学习方法-随机森林
  • CSP垦田计划
  • 磁带存储:“不老的传说”依然在继续
  • 数据结构(八)二叉树、哈希查找
  • Codeforces Round 948 (Div. 2) E. Tensor(思维题-交互)
  • 【前端学习——react坑】useState使用
  • 【笔记】你不知道的JS读书笔记——Promise
  • 2017-08-04 前端日报
  • canvas绘制圆角头像
  • CSS 专业技巧
  • C学习-枚举(九)
  • ECMAScript入门(七)--Module语法
  • ES6 ...操作符
  • JS进阶 - JS 、JS-Web-API与DOM、BOM
  • js中forEach回调同异步问题
  • LeetCode541. Reverse String II -- 按步长反转字符串
  • node和express搭建代理服务器(源码)
  • REST架构的思考
  • SpiderData 2019年2月13日 DApp数据排行榜
  • swift基础之_对象 实例方法 对象方法。
  • 动态魔术使用DBMS_SQL
  • 山寨一个 Promise
  • 深入浏览器事件循环的本质
  • 温故知新之javascript面向对象
  • 一天一个设计模式之JS实现——适配器模式
  • elasticsearch-head插件安装
  • #鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行
  • (10)Linux冯诺依曼结构操作系统的再次理解
  • (3)STL算法之搜索
  • (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
  • (初研) Sentence-embedding fine-tune notebook
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (附源码)计算机毕业设计SSM疫情下的学生出入管理系统
  • (简单) HDU 2612 Find a way,BFS。
  • (力扣)1314.矩阵区域和
  • (三维重建学习)已有位姿放入colmap和3D Gaussian Splatting训练
  • (一)认识微服务
  • ****三次握手和四次挥手
  • .Net 8.0 新的变化
  • .NetCore部署微服务(二)
  • /etc/fstab 只读无法修改的解决办法
  • /etc/motd and /etc/issue
  • @Transactional 竟也能解决分布式事务?
  • [ Linux ] git工具的基本使用(仓库的构建,提交)
  • [ 隧道技术 ] 反弹shell的集中常见方式(四)python反弹shell
  • [16/N]论得趣