【设计模式】迭代器模式 (游标(Cursor)模式)
迭代器模式(Iterator Pattern)详解
一、迭代器模式简介
迭代器模式(Iterator Pattern) 是一种 行为型设计模式(对象行为型模式),它提供了一种方法来顺序访问一个聚合对象中的各个元素,而无需暴露该对象的内部表示。换句话说,迭代器模式使得客户端可以通过统一的方式来遍历不同的集合类型(如数组、链表等),同时不需要了解这些集合的内部结构。
你可以把它想象成电视遥控器上的“下一个频道”按钮,无论你当前在观看哪个频道,按下这个按钮都会带你去到下一个频道,而你并不需要知道电视台是如何排列这些频道的。
电视机 <- -> 存储电视频道的集合 <- -> 聚合类(Aggregate Classes)
电视机遥控器 <- -> 操作电视频道 <- -> 迭代器(Iterator)
访问一个聚合对象中的元素但又不需要暴露它的内部结构
聚合对象的两个职责:
- 存储数据,聚合对象的基本职责
- 遍历数据,既是可变化的,又是可分离的
将遍历数据的行为从聚合对象中分离出来,封装在迭代器对象中
由迭代器来提供遍历聚合对象内部数据的行为,简化聚合对象的设计,更符合单一职责原则
迭代器模式:提供一种方法顺序访问一个聚合对象中各个元素,且不用暴露该对象的内部表示。
又名**游标(Cursor)**模式。
通过引入迭代器,客户端无须了解聚合对象的内部结构即可实现对聚合对象中成员的遍历,还可以根据需要很方便地增加新的遍历方式。
迭代器模式包含以下4个角色:
Iterator(抽象迭代器)
ConcreteIterator(具体迭代器)
Aggregate(抽象聚合类)
ConcreteAggregate(具体聚合类)
二、解决的问题类型
迭代器模式主要用于解决以下问题:
- 不同数据结构的遍历方式不一致:比如数组和链表有不同的遍历方式。
- 希望隐藏容器的内部实现细节:使客户端代码与具体的容器实现解耦。
- 支持多种遍历方式:例如前序遍历、中序遍历、后序遍历等。
- 为遍历不同的聚合结构提供一个统一的接口:在该接口的实现类中为不同的聚合结构提供不同的遍历方式,而客户端可以一致性地操作该接口。
- 访问一个聚合对象的内容而无须暴露它的内部表示
三、使用场景
场景 | 示例 |
---|---|
集合类库 | Java 的 ArrayList , HashSet 等都实现了 Iterable 接口 |
自定义集合类 | 当你需要为自定义的数据结构提供遍历功能时 |
复杂数据结构 | 如树形结构或图结构 |
四、核心概念
- Iterator(迭代器接口):定义了遍历操作的方法,如
hasNext()
,next()
, 和可选的remove()
。 - ConcreteIterator(具体迭代器):实现了 Iterator 接口,负责管理当前遍历的位置。
- Aggregate(聚合接口):定义了创建迭代器对象的方法
createIterator()
。 - ConcreteAggregate(具体聚合类):实现了 Aggregate 接口,返回一个 ConcreteIterator 实例。
五、实际代码案例(Java)
1. 定义 Iterator 接口
// 迭代器接口
public interface Iterator<T> {boolean hasNext();T next();
}
2. 定义 ConcreteIterator 类
// 具体迭代器类
class NameIterator implements Iterator<String> {private String[] names;private int position = 0;public NameIterator(String[] names) {this.names = names;}@Overridepublic boolean hasNext() {return position < names.length;}@Overridepublic String next() {if (this.hasNext()) {return names[position++];} else {return null;}}
}
3. 定义 Aggregate 接口
// 聚合接口
public interface Aggregate {Iterator createIterator();
}
4. 定义 ConcreteAggregate 类
// 具体聚合类
class NameCollection implements Aggregate {private String[] names;public NameCollection(String[] names) {this.names = names;}@Overridepublic Iterator createIterator() {return new NameIterator(names);}
}
5. 客户端测试类
public class Client {public static void main(String[] args) {String[] names = {"Alice", "Bob", "Charlie"};Aggregate collection = new NameCollection(names);Iterator iterator = collection.createIterator();while (iterator.hasNext()) {System.out.println(iterator.next());}}
}
输出结果:
Alice
Bob
Charlie
典型代码
典型的抽象迭代器代码
interface Iterator
{void First(); //将游标指向第一个元素void Next(); //将游标指向下一个元素bool HasNext(); //判断是否存在下一个元素object CurrentItem(); //获取游标指向的当前元素
}
典型的具体迭代器代码
class ConcreteIterator : Iterator
{private ConcreteAggregate objects; //维持一个对具体聚合对象的引用,以便于访问存储在聚合对象中的数据private int cursor; //定义一个游标,用于记录当前访问位置public ConcreteIterator(ConcreteAggregate objects) {this.objects = objects;}public void First() { //实现代码 } public void Next() { //实现代码 }public bool HasNext() { //实现代码} public object CurrentItem(){ //实现代码}
}
典型的抽象聚合类代码
interface Aggregate
{Iterator CreateIterator();
}
典型的具体聚合类代码
class ConcreteAggregate : Aggregate
{......public Iterator CreateIterator() {return new ConcreteIterator(this);}......
}
其他案例
- 某软件公司为某商场开发了一套销售管理系统,在对该系统进行分析
AbstractObjectList类的方法与说明
AbstractObjectList类的子类ProductList和CustomerList分别用于存储商品数据和客户数据。
通过分析,发现AbstractObjectList类的职责非常重,它既负责存储和管理数据,又负责遍历数据,违背了单一职责原则,实现代码将非常复杂。因此,开发人员决定使用迭代器模式对AbstractObjectList类进行重构,将负责遍历数据的方法提取出来,封装到专门的类中,实现数据存储和数据遍历分离,还可以给不同的具体数据集合类提供不同的遍历方式。
现给出使用迭代器模式重构后的解决方案。
- 电视机遥控器
电视机遥控器就是一个迭代器的实例,通过它可以实现对电视机频道集合的遍历操作,本实例我们将模拟电视机遥控器的实现。
六、优缺点分析
优点 | 描述 |
---|---|
✅ 简化了集合的遍历过程 | 提供了一致的遍历接口,便于维护和扩展, |
✅ 封装性良好 | 隐藏了集合的内部结构,增强了安全性,简化了聚合类 |
✅ 支持多种遍历方式 | 可以为同一集合提供不同的迭代器实现,在同一个聚合对象上可以定义多种遍历方式 |
其他 | 由于引入了抽象层,增加新的聚合类和迭代器类都很方便,无须修改原有代码,符合开闭原则 |
缺点 | 描述 |
---|---|
❌ 增加了系统复杂度 | 对于简单的集合遍历需求,引入迭代器模式可能显得过于复杂。在增加新的聚合类时需要对应地增加新的迭代器类,类的个数成对增加。 |
❌ 性能开销 | 创建迭代器实例会带来额外的内存消耗 |
其他 | 抽象迭代器的设计难度较大,需要充分考虑到系统将来的扩展。在自定义迭代器时,创建一个考虑全面的抽象迭代器并不是一件很容易的事情 |
七、与其他模式对比(补充)
模式名称 | 目标 |
---|---|
组合模式 | 处理树形结构的遍历 |
观察者模式 | 当对象状态变化时通知其他对象 |
迭代器模式 | 提供统一的遍历接口 |
八、最终小结
迭代器模式是一种非常实用的设计模式,特别适用于那些需要对不同类型的数据集合进行遍历操作的场景。通过应用迭代器模式,我们不仅能够简化集合的遍历逻辑,还能有效地将集合的具体实现细节与遍历算法分离,从而提高代码的灵活性和可维护性。
📌 一句话总结:
迭代器模式就像一个通用的遥控器,无论你的电视节目单(集合)如何组织,都能按顺序播放每一个节目(元素)。
✅ 推荐使用方式:
- 在需要对多种类型的集合进行遍历时;
- 希望保持集合类的封装性,不让外部直接访问其内部结构时;
- 支持多种遍历策略时。
部分内容由AI大模型生成,注意识别!