设计模式[16]——迭代器模式(Iterator)一分钟彻底说透(C++版·软件领域真实例子)
一句话定义
提供一种方法顺序访问一个聚合对象中的各个元素,而不暴露其内部表示,让遍历和容器完全解耦。
最狠的比喻(软件人专属)
STL容器遍历:
vector<int>vec={1,2,3,4};for(autoit=vec.begin();it!=vec.end();++it){cout<<*it;}// 或者 C++11: for (auto& x : vec)客户端完全不知道vector内部是连续数组,还是list是链表,还是set是红黑树——迭代器隐藏了一切细节!
为什么需要它?(坏味道瞬间爆炸)
不用迭代器,你会这样写:
// 对vectorfor(size_t i=0;i<vec.size();++i)cout<<vec[i];// 对listfor(autonode=list.head;node;node=node->next)cout<<node->data;// 对自定义容器?客户端每次换容器都得重写遍历代码,寄!和之前模式彻底分清(10秒表)
| 项目 | 命令(Command) | 解释器(Interpreter) | 迭代器(Iterator) |
|---|---|---|---|
| 核心意图 | 操作封装成对象 | 解释语法树 | 统一遍历不同容器 |
| 关键操作 | execute()/undo() | interpret()递归 | ++it / *it / it != end() |
| 关注点 | 行为封装 | 语法执行 | 访问顺序,不暴露内部结构 |
| 典型场景 | 撤销重做 | 规则引擎/表达式 | STL容器、树遍历、数据库游标 |
| 口号 | “命令即对象” | “语法树里走一遭” | “换容器不换遍历代码” |
真实软件例子:统一遍历不同容器(自定义+STL)
#include<iostream>#include<vector>#include<list>#include<memory>usingnamespacestd;// 1. 迭代器接口(C++标准风格)template<typenameT>classIterator{public:virtual~Iterator()=default;virtualboolhasNext()const=0;virtualTnext()=0;};// 2. 具体容器:动态数组template<typenameT>classVectorContainer{vector<T>data;public:voidadd(constT&item){data.push_back(item);}classVecIterator:publicIterator<T>{typenamevector<T>::iterator it,end;// 注意C++11+可以用autopublic:VecIterator(typenamevector<T>::iterator begin,typenamevector<T>::iterator e):it(begin),end(e){}boolhasNext()constoverride{returnit!=end;}Tnext()override{return*it++;}};unique_ptr<Iterator<T>>createIterator(){returnmake_unique<VecIterator>(data.begin(),data.end());}};// 3. 具体容器:链表template<typenameT>classListContainer{list<T>data;public:voidadd(constT&item){data.push_back(item);}classListIterator:publicIterator<T>{typenamelist<T>::iterator it,end;public:ListIterator(typenamelist<T>::iterator begin,typenamelist<T>::iterator e):it(begin),end(e){}boolhasNext()constoverride{returnit!=end;}Tnext()override{return*it++;}};unique_ptr<Iterator<T>>createIterator(){returnmake_unique<ListIterator>(data.begin(),data.end());}};客户端:统一遍历代码,换容器无感
intmain(){VectorContainer<string>vecCont;vecCont.add("Alice");vecCont.add("Bob");vecCont.add("Charlie");ListContainer<string>listCont;listCont.add("Dave");listCont.add("Eve");listCont.add("Frank");// 统一遍历函数(客户端代码完全相同!)autoprintAll=[](auto&container){autoiter=container.createIterator();while(iter->hasNext()){cout<<iter->next()<<" ";}cout<<endl;};cout<<"遍历Vector容器: ";printAll(vecCont);// Alice Bob Charliecout<<"遍历List容器: ";printAll(listCont);// Dave Eve Frank// 明天换set、map、自定义树?客户端一行代码不动!}输出:
遍历Vector容器: Alice Bob Charlie 遍历List容器: Dave Eve FrankC++ 真实项目里无处不在
- STL全家桶:vector::iterator、list::iterator、map::iterator、set::iterator
- 范围for循环:本质就是begin()/end()迭代器
- 数据库游标:ResultSet的next()遍历行
- 树/图遍历:前序/中序/后序迭代器(非递归版)
- Boost.Iterator:各种高级迭代器适配器
现代C++更爽写法(C++20)
for(constauto&item:container){...}// 自动调用begin/end// 自定义容器只需重载begin()和end()即可支持范围for!终极口诀(STL使用者专属)
“容器千千万,遍历只一行;
迭代器统一,内部随便藏!”
刻在DNA里的一句话
当你有“多种不同结构的容器”,却希望客户端用完全统一的代码遍历时,
立刻上迭代器模式——提供begin/hasNext/next,换底层实现客户端无感!
现在,迭代器模式(STL的灵魂)彻底说透了!