迭代器模式
迭代器模式中文讲解
迭代器模式(Iterator Pattern)是一种行为型设计模式,属于 GoF(Gang of Four)提出的23种设计模式之一。它的核心目标是提供一种方法来顺序访问聚合对象(集合)的元素,而无需暴露集合的内部结构。迭代器模式将遍历逻辑从集合对象中分离出来,使客户端可以通过统一接口访问元素,增强了代码的灵活性和可维护性。
以下用中文详细讲解迭代器模式的定义、结构、代码示例、应用场景、优缺点以及在 Servlet 环境中的使用,重点突出其原理和实际应用。
1. 什么是迭代器模式?
迭代器模式通过定义一个迭代器对象,允许客户端顺序访问集合中的元素,而无需了解集合的底层实现(如数组、链表、树)。它解决了以下问题:
- 问题:直接操作集合的内部结构(如数组索引、链表节点)会导致客户端代码与集合实现耦合,且遍历逻辑重复。
- 解决方案:定义迭代器接口,提供
hasNext()
和next()
方法,封装遍历逻辑,客户端通过迭代器访问元素。
关键特点:
- 封装遍历:隐藏集合的内部结构,提供统一访问方式。
- 解耦:客户端与集合实现分离,仅依赖迭代器接口。
- 灵活性:支持多种遍历方式(如顺序、逆序)。
2. 迭代器模式的结构
迭代器模式包含以下角色:
角色 | 描述 |
---|---|
抽象迭代器(Iterator) | 定义迭代器接口,声明 hasNext() 和 next() 方法,可能包括其他方法如 remove() 。 |
具体迭代器(Concrete Iterator) | 实现迭代器接口,跟踪遍历位置,访问集合元素。 |
抽象聚合(Aggregate) | 定义集合接口,声明创建迭代器的方法(如 createIterator() )。 |
具体聚合(Concrete Aggregate) | 实现聚合接口,存储元素,提供迭代器创建方法。 |
客户端(Client) | 使用迭代器接口遍历集合元素。 |
UML 类图(文字描述):
- Iterator:接口,声明
hasNext()
、next()
方法。 - ConcreteIterator:实现 Iterator,维护遍历状态(如索引或指针)。
- Aggregate:接口,声明
createIterator()
方法。 - ConcreteAggregate:实现 Aggregate,存储数据,返回 ConcreteIterator。
- 客户端通过 Aggregate 获取 Iterator,调用
hasNext()
和next()
遍历。
Java 内置支持:Java 的 java.util.Iterator
和 Iterable
接口是迭代器模式的典型实现,集合类(如 ArrayList
、HashMap
)都支持。
3. 代码示例
以下是一个 Java 示例,模拟书架(BookShelf)存储书籍,并通过迭代器遍历。
// 抽象迭代器
interface Iterator {
boolean hasNext();
Object next();
}
// 抽象聚合
interface Aggregate {
Iterator createIterator();
}
// 具体聚合:书架
class BookShelf implements Aggregate {
private String[] books;
private int size;
public BookShelf(int capacity) {
books = new String[capacity];
size = 0;
}
public void addBook(String book) {
if (size < books.length) {
books[size++] = book;
}
}
@Override
public Iterator createIterator() {
return new BookShelfIterator(this);
}
public String getBookAt(int index) {
return books[index];
}
public int getSize() {
return size;
}
}
// 具体迭代器
class BookShelfIterator implements Iterator {
private BookShelf bookShelf;
private int index;
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0;
}
@Override
public boolean hasNext() {
return index < bookShelf.getSize();
}
@Override
public Object next() {
return bookShelf.getBookAt(index++);
}
}
// 测试
public class IteratorTest {
public static void main(String[] args) {
// 创建书架
BookShelf bookShelf = new BookShelf(4);
bookShelf.addBook("设计模式");
bookShelf.addBook("算法导论");
bookShelf.addBook("Java 编程思想");
// 获取迭代器
Iterator iterator = bookShelf.createIterator();
// 遍历
while (iterator.hasNext()) {
String book = (String) iterator.next();
System.out.println("书籍: " + book);
}
}
}
输出:
书籍: 设计模式
书籍: 算法导论
书籍: Java 编程思想
说明:
Iterator
是抽象迭代器,定义hasNext()
和next()
。Aggregate
是抽象聚合,声明createIterator()
。BookShelf
是具体聚合,存储书籍数组,返回迭代器。BookShelfIterator
是具体迭代器,跟踪遍历位置。- 客户端通过迭代器遍历书架,无需了解内部数组结构。
Java 内置迭代器示例:
import java.util.ArrayList;
import java.util.Iterator;
public class JavaIteratorTest {
public static void main(String[] args) {
ArrayList<String> books = new ArrayList<>();
books.add("设计模式");
books.add("算法导论");
Iterator<String> iterator = books.iterator();
while (iterator.hasNext()) {
System.out.println("书籍: " + iterator.next());
}
}
}
4. 迭代器模式的应用场景
- 集合遍历:如 Java 的 List、Set、Map 遍历。
- 复杂数据结构:如树、图的遍历(前序、后序、广度优先)。
- 数据库查询:遍历结果集(如 JDBC 的
ResultSet
)。 - Servlet 相关:遍历请求参数、会话属性或响应数据。
Servlet 示例:遍历请求参数并生成响应。
import javax.servlet.http.*;
import java.io.IOException;
import java.util.Enumeration;
// Servlet
public class ParameterIteratorServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.setContentType("text/html;charset=UTF-8");
StringBuilder html = new StringBuilder("<h1>请求参数</h1><ul>");
// 获取参数迭代器
Enumeration<String> paramNames = req.getParameterNames();
// 遍历参数
while (paramNames.hasMoreElements()) {
String paramName = paramNames.nextElement();
String paramValue = req.getParameter(paramName);
html.append("<li>").append(paramName).append(": ").append(paramValue).append("</li>");
}
html.append("</ul>");
resp.getWriter().write(html.toString());
}
}
输出(访问 /params?name=张三&role=admin
):
<h1>请求参数</h1>
<ul>
<li>name: 张三</li>
<li>role: admin</li>
</ul>
说明:
Enumeration
是 Java 早期的迭代器接口,类似Iterator
。- Servlet 使用
req.getParameterNames()
获取参数名迭代器,遍历并生成 HTML。 - 客户端无需知道参数存储方式,解耦遍历逻辑。
5. 迭代器模式的优缺点
优点:
- 解耦:客户端与集合实现分离,仅依赖迭代器接口。
- 统一接口:提供标准遍历方式(如
hasNext()
、next()
)。 - 灵活性:支持多种遍历方式(如正序、逆序)。
- 符合单一职责:遍历逻辑从集合中分离。
缺点:
- 复杂性:为简单集合实现迭代器可能增加代码量。
- 性能开销:迭代器对象可能带来少量开销。
- 适用范围有限:适合顺序访问,不适合随机访问或复杂操作。
6. 注意事项
- 迭代器设计:
- 迭代器应维护遍历状态(如索引、指针),避免外部修改。
- 支持
remove()
等操作需确保集合一致性。
- 中文编码问题:
- 如果涉及中文(如参数值),确保 Servlet 使用 UTF-8:
java resp.setContentType("text/html;charset=UTF-8");
- 对中文参数解码(如
URLDecoder.decode("张三", "UTF-8")
)。
- 线程安全:
- 迭代器在多线程环境可能抛
ConcurrentModificationException
。 - 使用线程安全集合(如
CopyOnWriteArrayList
)或同步迭代器。
- 性能优化:
- 避免创建过多迭代器,复用现有迭代器。
- 对于简单集合,直接遍历可能更高效。
- 与其他模式结合:
- 组合模式:遍历树形结构(如菜单、文件系统)。
- 工厂模式:动态创建迭代器。
- 访问者模式:为集合元素添加操作。
- 常见问题解决:
- 并发修改:使用
Iterator
的remove()
或线程安全集合。 - 遍历中断:检查
hasNext()
逻辑,确保正确终止。 - 中文乱码:统一编码为 UTF-8。
7. 与其他模式的区别
特性 | 迭代器模式 | 访问者模式 | 组合模式 |
---|---|---|---|
目的 | 遍历集合元素 | 为元素添加操作 | 表示部分-整体层次 |
实现方式 | 迭代器接口 | 访问者接口 | 树形结构 |
关注点 | 顺序访问 | 操作扩展 | 统一接口 |
客户端交互 | 通过迭代器遍历 | 通过访问者操作 | 通过组件接口 |
8. 总结
- 迭代器模式通过封装遍历逻辑,提供统一方式访问集合元素,解耦客户端与集合实现。
- 核心是抽象迭代器、具体迭代器、抽象聚合和具体聚合。
- 在 Servlet 中,可用于遍历请求参数或会话属性。
- 优点是解耦和灵活性,缺点是复杂性和性能开销。
- 注意中文编码、线程安全和迭代器状态管理。
如果需要更复杂的示例(如树形结构迭代、自定义迭代器)、Servlet 集成细节,或与其他模式(如组合、访问者)的深入对比,请告诉我!