Iterator 适用于:1.访问一个聚合对象的内容而无需暴露它的内部表示。2.支持对聚合对象的多种遍历。3.对遍历不同的聚合结构提供一个统一的接口(即,支持多态迭代)。
2.结构图
3.注意事项
1)谁控制迭代器,不由客户控制迭代时,称为外部迭代器(external iterator),而当由迭代器控制时,称为内部迭代器(internal iterator)。使用外部迭代器,客户必须主动推进遍历的步伐,显式地向迭代器请求下一个元素。相反,使用内部迭代器时,客户只需提交一个执行请求,而迭代器将对聚合中的每一个元素实施该操作。 外部迭代器比内部迭代器更灵活。
2)谁定义遍历算法,聚合本身可以定义遍历算法,并在遍历过程中用迭代器来存储当前迭代的状态,这种迭代器称为一个游标,因为它仅用来指示当前位置。如果由迭代器负责遍历算法,那么将易于在相同的聚合上使用不同的迭代算法,同时也易于在不同的聚合上重用相同的算法。但同时,将遍历算法放入迭代器中会破坏聚合的封装性。
3)迭代器的健壮性非常重要,一个健壮的迭代器(robust iterator)保证插入和删除操作不会干扰遍历,且不需拷贝该聚合。不过有时还是很难做到。
4)在 C++ 中使用多态的迭代器,使用多态迭代器是有代价的。它们要求用一个 Factory Method 动态的分配迭代器对象。因此仅当必须多态时才使用它们,否则使用在栈中分配内存的具体的迭代器。多态迭代器有另一个缺点:客户必须负责删除它们。Proxy 为此提供了一种补救方法,我们可以使用一个栈分配的 Proxy 作为实际迭代器的中间代理。该代理在其析构器中删除该迭代器。这样当该代理生命周期结束时,实际迭代器将同它一起释放,即使在发生异常时,该代理机制能保证正确地清除迭代器对象,这就是著名的C++“资源分配即初始化”技术的一个应用。
5)空迭代器,一个空迭代器(Null Iterator)是一个退化的迭代器,它有助于处理边界条件。一个 NullIterator 总是已经完成了遍历,即它的 IsDone 操作总是返回 true。等还有其它比较复杂的注意事项。