迭代器模式大白话讲解
一句话概括
就像DVD遥控器:你不用知道电影是怎么存储在光盘上的,按下一曲就能看到下一段内容
现实生活比喻
场景1:DVD播放器
- DVD光盘:存储了整部电影(聚合对象)
- 遥控器:迭代器
- 你:客户端
- 过程:你按"下一曲"按钮,不用关心光盘怎么存储,就能看到下一段
场景2:书架上的书
- 书架:书集合(聚合对象)
- 你的手指:迭代器
- 你:客户端
- 过程:你用手指一本本划过书架,不用关心书架的结构,就能遍历所有书
完整代码示例
场景1:电视频道迭代器
java
/**
* 迭代器模式 - 电视频道管理
*/
public class Main {
public static void main(String[] args) {
System.out.println("=== 电视频道管理系统 ===");
// 创建电视频道集合
ChannelCollection channels = new ChannelCollectionImpl();
// 添加一些频道
channels.addChannel(new Channel(1, "CCTV-1", "综合频道"));
channels.addChannel(new Channel(2, "CCTV-2", "财经频道"));
channels.addChannel(new Channel(3, "CCTV-5", "体育频道"));
channels.addChannel(new Channel(4, "湖南卫视", "娱乐频道"));
channels.addChannel(new Channel(5, "浙江卫视", "娱乐频道"));
channels.addChannel(new Channel(6, "CCTV-13", "新闻频道"));
channels.addChannel(new Channel(7, "凤凰卫视", "新闻频道"));
channels.addChannel(new Channel(8, "Discovery", "纪录片频道"));
// 普通遍历所有频道
System.out.println("\n--- 所有电视频道 ---");
ChannelIterator iterator = channels.createIterator();
while (iterator.hasNext()) {
Channel channel = iterator.next();
System.out.println(channel);
}
// 按类型遍历
System.out.println("\n--- 娱乐频道 ---");
ChannelIterator entertainmentIterator = channels.createIteratorByType("娱乐频道");
while (entertainmentIterator.hasNext()) {
Channel channel = entertainmentIterator.next();
System.out.println(channel);
}
System.out.println("\n--- 新闻频道 ---");
ChannelIterator newsIterator = channels.createIteratorByType("新闻频道");
while (newsIterator.hasNext()) {
Channel channel = newsIterator.next();
System.out.println(channel);
}
// 反向遍历
System.out.println("\n--- 反向遍历所有频道 ---");
ChannelIterator reverseIterator = channels.createReverseIterator();
while (reverseIterator.hasNext()) {
Channel channel = reverseIterator.next();
System.out.println(channel);
}
}
}
/**
* 电视频道类
*/
class Channel {
private int number;
private String name;
private String type;
public Channel(int number, String name, String type) {
this.number = number;
this.name = name;
this.type = type;
}
public int getNumber() { return number; }
public String getName() { return name; }
public String getType() { return type; }
@Override
public String toString() {
return "频道" + number + ": " + name + " (" + type + ")";
}
}
/**
* 迭代器接口
*/
interface ChannelIterator {
boolean hasNext();
Channel next();
void reset();
}
/**
* 具体迭代器 - 普通迭代器
*/
class ChannelIteratorImpl implements ChannelIterator {
private List<Channel> channels;
private int position;
public ChannelIteratorImpl(List<Channel> channels) {
this.channels = channels;
this.position = 0;
}
@Override
public boolean hasNext() {
return position < channels.size();
}
@Override
public Channel next() {
if (!hasNext()) {
throw new NoSuchElementException("没有更多频道了");
}
Channel channel = channels.get(position);
position++;
return channel;
}
@Override
public void reset() {
position = 0;
}
}
/**
* 具体迭代器 - 按类型过滤的迭代器
*/
class ChannelTypeIterator implements ChannelIterator {
private List<Channel> channels;
private String type;
private int position;
public ChannelTypeIterator(List<Channel> channels, String type) {
this.channels = channels;
this.type = type;
this.position = 0;
}
@Override
public boolean hasNext() {
// 找到下一个符合类型的频道
while (position < channels.size()) {
if (channels.get(position).getType().equals(type)) {
return true;
}
position++;
}
return false;
}
@Override
public Channel next() {
if (!hasNext()) {
throw new NoSuchElementException("没有更多" + type + "频道了");
}
Channel channel = channels.get(position);
position++;
return channel;
}
@Override
public void reset() {
position = 0;
}
}
/**
* 具体迭代器 - 反向迭代器
*/
class ReverseChannelIterator implements ChannelIterator {
private List<Channel> channels;
private int position;
public ReverseChannelIterator(List<Channel> channels) {
this.channels = channels;
this.position = channels.size() - 1; // 从最后开始
}
@Override
public boolean hasNext() {
return position >= 0;
}
@Override
public Channel next() {
if (!hasNext()) {
throw new NoSuchElementException("没有更多频道了");
}
Channel channel = channels.get(position);
position--;
return channel;
}
@Override
public void reset() {
position = channels.size() - 1;
}
}
/**
* 聚合接口 - 频道集合
*/
interface ChannelCollection {
void addChannel(Channel channel);
void removeChannel(Channel channel);
ChannelIterator createIterator();
ChannelIterator createIteratorByType(String type);
ChannelIterator createReverseIterator();
}
/**
* 具体聚合 - 频道集合实现
*/
class ChannelCollectionImpl implements ChannelCollection {
private List<Channel> channels = new ArrayList<>();
@Override
public void addChannel(Channel channel) {
channels.add(channel);
}
@Override
public void removeChannel(Channel channel) {
channels.remove(channel);
}
@Override
public ChannelIterator createIterator() {
return new ChannelIteratorImpl(channels);
}
@Override
public ChannelIterator createIteratorByType(String type) {
return new ChannelTypeIterator(channels, type);
}
@Override
public ChannelIterator createReverseIterator() {
return new ReverseChannelIterator(channels);
}
}
运行结果
=== 电视频道管理系统 ===
--- 所有电视频道 ---
频道1: CCTV-1 (综合频道)
频道2: CCTV-2 (财经频道)
频道3: CCTV-5 (体育频道)
频道4: 湖南卫视 (娱乐频道)
频道5: 浙江卫视 (娱乐频道)
频道6: CCTV-13 (新闻频道)
频道7: 凤凰卫视 (新闻频道)
频道8: Discovery (纪录片频道)
--- 娱乐频道 ---
频道4: 湖南卫视 (娱乐频道)
频道5: 浙江卫视 (娱乐频道)
--- 新闻频道 ---
频道6: CCTV-13 (新闻频道)
频道7: 凤凰卫视 (新闻频道)
--- 反向遍历所有频道 ---
频道8: Discovery (纪录片频道)
频道7: 凤凰卫视 (新闻频道)
频道6: CCTV-13 (新闻频道)
频道5: 浙江卫视 (娱乐频道)
频道4: 湖南卫视 (娱乐频道)
频道3: CCTV-5 (体育频道)
频道2: CCTV-2 (财经频道)
频道1: CCTV-1 (综合频道)

场景2:文件系统遍历器
java
/**
* 迭代器模式 - 文件系统遍历
*/
public class FileSystemExample {
public static void main(String[] args) {
System.out.println("=== 文件系统遍历 ===");
// 构建一个文件系统树
FileSystemItem root = new Directory("root");
Directory docs = new Directory("文档");
docs.addItem(new File("简历.doc", 200));
docs.addItem(new File("报告.pdf", 500));
Directory photos = new Directory("照片");
photos.addItem(new File("毕业照.jpg", 1500));
photos.addItem(new File("旅游照.jpg", 1200));
Directory music = new Directory("音乐");
music.addItem(new File("歌曲1.mp3", 8000));
music.addItem(new File("歌曲2.mp3", 7500));
root.addItem(docs);
root.addItem(photos);
root.addItem(music);
// 创建不同的迭代器
System.out.println("\n--- 深度优先遍历 ---");
FileSystemIterator dfsIterator = root.createDepthFirstIterator();
while (dfsIterator.hasNext()) {
FileSystemItem item = dfsIterator.next();
System.out.println(item);
}
System.out.println("\n--- 只遍历文件(过滤文件夹) ---");
FileSystemIterator fileOnlyIterator = root.createFileOnlyIterator();
while (fileOnlyIterator.hasNext()) {
FileSystemItem item = fileOnlyIterator.next();
System.out.println(item);
}
System.out.println("\n--- 按大小过滤(大于1MB的文件) ---");
FileSystemIterator largeFileIterator = root.createLargeFileIterator(1000);
while (largeFileIterator.hasNext()) {
FileSystemItem item = largeFileIterator.next();
System.out.println(item);
}
// 计算总大小
System.out.println("\n=== 文件统计 ===");
int totalSize = 0;
FileSystemIterator sizeIterator = root.createFileOnlyIterator();
while (sizeIterator.hasNext()) {
FileSystemItem item = sizeIterator.next();
totalSize += ((File) item).getSize();
}
System.out.println("所有文件总大小: " + totalSize + "KB");
}
}
/**
* 文件系统项接口
*/
interface FileSystemItem {
String getName();
FileSystemIterator createDepthFirstIterator();
FileSystemIterator createFileOnlyIterator();
FileSystemIterator createLargeFileIterator(int minSizeKB);
}
/**
* 文件类
*/
class File implements FileSystemItem {
private String name;
private int size; // KB
public File(String name, int size) {
this.name = name;
this.size = size;
}
@Override
public String getName() {
return name;
}
public int getSize() {
return size;
}
@Override
public FileSystemIterator createDepthFirstIterator() {
return new SingleItemIterator(this);
}
@Override
public FileSystemIterator createFileOnlyIterator() {
return new SingleItemIterator(this);
}
@Override
public FileSystemIterator createLargeFileIterator(int minSizeKB) {
if (size >= minSizeKB) {
return new SingleItemIterator(this);
}
return new EmptyIterator();
}
@Override
public String toString() {
return "文件: " + name + " (" + size + "KB)";
}
}
/**
* 目录类
*/
class Directory implements FileSystemItem {
private String name;
private List<FileSystemItem> items = new ArrayList<>();
public Directory(String name) {
this.name = name;
}
public void addItem(FileSystemItem item) {
items.add(item);
}
@Override
public String getName() {
return name;
}
@Override
public FileSystemIterator createDepthFirstIterator() {
return new DepthFirstIterator(this);
}
@Override
public FileSystemIterator createFileOnlyIterator() {
return new FileOnlyIterator(this);
}
@Override
public FileSystemIterator createLargeFileIterator(int minSizeKB) {
return new LargeFileIterator(this, minSizeKB);
}
public List<FileSystemItem> getItems() {
return items;
}
@Override
public String toString() {
return "目录: [" + name + "]";
}
}
/**
* 文件系统迭代器接口
*/
interface FileSystemIterator {
boolean hasNext();
FileSystemItem next();
}
/**
* 具体迭代器 - 深度优先迭代器
*/
class DepthFirstIterator implements FileSystemIterator {
private Stack<FileSystemItem> stack = new Stack<>();
public DepthFirstIterator(FileSystemItem root) {
stack.push(root);
}
@Override
public boolean hasNext() {
return !stack.isEmpty();
}
@Override
public FileSystemItem next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
FileSystemItem current = stack.pop();
// 如果是目录,将其子项逆序压入栈中(保证正序遍历)
if (current instanceof Directory) {
List<FileSystemItem> items = ((Directory) current).getItems();
for (int i = items.size() - 1; i >= 0; i--) {
stack.push(items.get(i));
}
}
return current;
}
}
/**
* 具体迭代器 - 只遍历文件的迭代器
*/
class FileOnlyIterator implements FileSystemIterator {
private Stack<FileSystemItem> stack = new Stack<>();
public FileOnlyIterator(FileSystemItem root) {
stack.push(root);
}
@Override
public boolean hasNext() {
// 跳过目录,只找文件
while (!stack.isEmpty() && stack.peek() instanceof Directory) {
FileSystemItem current = stack.pop();
List<FileSystemItem> items = ((Directory) current).getItems();
for (int i = items.size() - 1; i >= 0; i--) {
stack.push(items.get(i));
}
}
return !stack.isEmpty();
}
@Override
public FileSystemItem next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return stack.pop();
}
}
/**
* 具体迭代器 - 大文件迭代器
*/
class LargeFileIterator implements FileSystemIterator {
private Stack<FileSystemItem> stack = new Stack<>();
private int minSizeKB;
private FileSystemItem nextFile;
public LargeFileIterator(FileSystemItem root, int minSizeKB) {
this.minSizeKB = minSizeKB;
stack.push(root);
findNext();
}
private void findNext() {
nextFile = null;
while (!stack.isEmpty() && nextFile == null) {
FileSystemItem current = stack.pop();
if (current instanceof File) {
if (((File) current).getSize() >= minSizeKB) {
nextFile = current;
}
} else if (current instanceof Directory) {
List<FileSystemItem> items = ((Directory) current).getItems();
for (int i = items.size() - 1; i >= 0; i--) {
stack.push(items.get(i));
}
}
}
}
@Override
public boolean hasNext() {
return nextFile != null;
}
@Override
public FileSystemItem next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
FileSystemItem result = nextFile;
findNext();
return result;
}
}
/**
* 单项目迭代器(用于文件)
*/
class SingleItemIterator implements FileSystemIterator {
private FileSystemItem item;
private boolean consumed = false;
public SingleItemIterator(FileSystemItem item) {
this.item = item;
}
@Override
public boolean hasNext() {
return !consumed;
}
@Override
public FileSystemItem next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
consumed = true;
return item;
}
}
/**
* 空迭代器
*/
class EmptyIterator implements FileSystemIterator {
@Override
public boolean hasNext() {
return false;
}
@Override
public FileSystemItem next() {
throw new NoSuchElementException();
}
}
运行结果
=== 文件系统遍历 ===
--- 深度优先遍历 ---
目录: [root]
目录: [音乐]
文件: 歌曲2.mp3 (7500KB)
文件: 歌曲1.mp3 (8000KB)
目录: [照片]
文件: 旅游照.jpg (1200KB)
文件: 毕业照.jpg (1500KB)
目录: [文档]
文件: 报告.pdf (500KB)
文件: 简历.doc (200KB)
--- 只遍历文件(过滤文件夹) ---
文件: 歌曲2.mp3 (7500KB)
文件: 歌曲1.mp3 (8000KB)
文件: 旅游照.jpg (1200KB)
文件: 毕业照.jpg (1500KB)
文件: 报告.pdf (500KB)
文件: 简历.doc (200KB)
--- 按大小过滤(大于1MB的文件) ---
文件: 歌曲2.mp3 (7500KB)
文件: 歌曲1.mp3 (8000KB)
文件: 旅游照.jpg (1200KB)
文件: 毕业照.jpg (1500KB)
=== 文件统计 ===
所有文件总大小: 18900KB
迭代器模式的核心结构
Aggregate(聚合接口)
↑
ConcreteAggregate(具体聚合) → createIterator()
↓ 返回
Iterator(迭代器接口)
↑
ConcreteIterator(具体迭代器) → 遍历内部集合
关键特征:
- 封装遍历:将遍历逻辑从集合中分离出来
- 统一接口:不同的集合提供相同的遍历接口
- 多种遍历方式:可以同时进行多个遍历
- 隐藏实现:客户端不知道集合的内部结构
Java中的迭代器
Java集合框架中的迭代器
java
// Java的Collection接口都实现了Iterable
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
// 使用迭代器
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println(item);
}
// 增强for循环(底层使用迭代器)
for (String item : list) {
System.out.println(item);
}
自定义可迭代对象
java
class MyCollection implements Iterable<String> {
private String[] items = {"A", "B", "C"};
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
private int index = 0;
@Override
public boolean hasNext() {
return index < items.length;
}
@Override
public String next() {
return items[index++];
}
};
}
}
迭代器模式的几种类型
1. 外部迭代器(客户端控制迭代)
java
// 客户端显式调用next()和hasNext()
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
Object item = iterator.next();
// 处理item
}
2. 内部迭代器(迭代器控制迭代)
java
// 客户端提供处理函数,迭代器控制循环
collection.forEach(item -> {
// 处理item
});
3. 游标迭代器(C++风格)
java
// 使用begin()和end()方法
for (Iterator it = collection.begin(); it != collection.end(); it++) {
Object item = it.get();
}
适用场景(大白话版)
✅ 适合用迭代器模式的场景:
-
需要多种遍历方式
java// 正序遍历、逆序遍历、按条件过滤遍历 // 树结构的深度优先、广度优先遍历 -
需要统一遍历接口
java// 不同类型的集合(数组、链表、树)提供相同的遍历方式 // 客户端代码不需要知道集合的具体类型 -
隐藏集合内部结构
java// 集合的内部实现可能改变,但迭代接口不变 // 今天用数组,明天可能改成链表,客户端代码不用改
❌ 不适合的场景:
- 简单集合:如果集合非常简单,直接遍历即可
- 只需要一种遍历方式:如果只有一种遍历需求
- 性能敏感:迭代器调用有额外开销
优缺点
优点:
- 简化客户端代码:客户端只需要调用统一接口
- 支持多种遍历:可以为同一集合提供不同遍历方式
- 封装集合内部:集合的内部结构变化不影响客户端
- 开闭原则:新增迭代器不影响现有代码
缺点:
- 增加复杂度:对于简单集合显得过度设计
- 性能开销:迭代器调用比直接访问稍慢
- 遍历状态:并发修改可能导致问题
与foreach循环的关系
java
// Java的foreach循环就是迭代器模式的语法糖
List<String> list = Arrays.asList("A", "B", "C");
// 写法1:foreach循环(简洁)
for (String item : list) {
System.out.println(item);
}
// 写法2:显式迭代器(灵活)
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println(item);
// 迭代器可以做更多事情
if (item.equals("B")) {
iterator.remove(); // 删除当前元素
}
}
实际应用案例
1. Java集合框架
java
// List、Set、Map等都支持迭代器
List<String> list = new ArrayList<>();
Set<String> set = new HashSet<>();
Map<String, Integer> map = new HashMap<>();
// 都有统一的迭代方式
for (String item : list) { ... }
for (String item : set) { ... }
for (Map.Entry<String, Integer> entry : map.entrySet()) { ... }
2. 数据库结果集
java
// JDBC的ResultSet就是迭代器模式
ResultSet rs = statement.executeQuery("SELECT * FROM users");
while (rs.next()) { // hasNext()
String name = rs.getString("name"); // next()
int age = rs.getInt("age");
}
3. 文件读取
java
// 按行读取文件
BufferedReader reader = new BufferedReader(new FileReader("file.txt"));
String line;
while ((line = reader.readLine()) != null) { // hasNext()和next()的结合
System.out.println(line);
}
reader.close();
4. 流处理
java
// Java 8的Stream API是增强的迭代器
list.stream()
.filter(s -> s.startsWith("A"))
.map(String::toUpperCase)
.forEach(System.out::println);
总结
迭代器模式就是:
- 遥控器:控制播放进度,不用知道光盘结构
- 导游:带你游览景点,不用自己找路
- 取票机:一张张出票,不用知道票库结构
- 翻书:一页页翻看,不用知道书怎么装订
核心口诀:
集合遍历太麻烦,
各种结构不一般。
迭代模式来统一,
隐藏细节真简单!
就像现实中的:
- 📺 电视遥控器:换台不看电路板
- 📚 图书馆索书号:按号找书不看书架结构
- 🎵 音乐播放列表:下一首不看文件存储
- 🗺️ 地图导航:路线规划不看地图数据存储
记住:当你需要遍历一个集合,但又不想暴露它的内部结构时,考虑使用迭代器模式!