迭代器模式

迭代器模式中文讲解

迭代器模式(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.IteratorIterable 接口是迭代器模式的典型实现,集合类(如 ArrayListHashMap)都支持。


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. 迭代器模式的优缺点

优点

  1. 解耦:客户端与集合实现分离,仅依赖迭代器接口。
  2. 统一接口:提供标准遍历方式(如 hasNext()next())。
  3. 灵活性:支持多种遍历方式(如正序、逆序)。
  4. 符合单一职责:遍历逻辑从集合中分离。

缺点

  1. 复杂性:为简单集合实现迭代器可能增加代码量。
  2. 性能开销:迭代器对象可能带来少量开销。
  3. 适用范围有限:适合顺序访问,不适合随机访问或复杂操作。

6. 注意事项

  1. 迭代器设计
  • 迭代器应维护遍历状态(如索引、指针),避免外部修改。
  • 支持 remove() 等操作需确保集合一致性。
  1. 中文编码问题
  • 如果涉及中文(如参数值),确保 Servlet 使用 UTF-8:
    java resp.setContentType("text/html;charset=UTF-8");
  • 对中文参数解码(如 URLDecoder.decode("张三", "UTF-8"))。
  1. 线程安全
  • 迭代器在多线程环境可能抛 ConcurrentModificationException
  • 使用线程安全集合(如 CopyOnWriteArrayList)或同步迭代器。
  1. 性能优化
  • 避免创建过多迭代器,复用现有迭代器。
  • 对于简单集合,直接遍历可能更高效。
  1. 与其他模式结合
  • 组合模式:遍历树形结构(如菜单、文件系统)。
  • 工厂模式:动态创建迭代器。
  • 访问者模式:为集合元素添加操作。
  1. 常见问题解决
  • 并发修改:使用 Iteratorremove() 或线程安全集合。
  • 遍历中断:检查 hasNext() 逻辑,确保正确终止。
  • 中文乱码:统一编码为 UTF-8。

7. 与其他模式的区别

特性迭代器模式访问者模式组合模式
目的遍历集合元素为元素添加操作表示部分-整体层次
实现方式迭代器接口访问者接口树形结构
关注点顺序访问操作扩展统一接口
客户端交互通过迭代器遍历通过访问者操作通过组件接口

8. 总结

  • 迭代器模式通过封装遍历逻辑,提供统一方式访问集合元素,解耦客户端与集合实现。
  • 核心是抽象迭代器、具体迭代器、抽象聚合和具体聚合。
  • 在 Servlet 中,可用于遍历请求参数或会话属性。
  • 优点是解耦和灵活性,缺点是复杂性和性能开销。
  • 注意中文编码、线程安全和迭代器状态管理。

如果需要更复杂的示例(如树形结构迭代、自定义迭代器)、Servlet 集成细节,或与其他模式(如组合、访问者)的深入对比,请告诉我!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注