跳至正文
来两杯美式
返回

设计模式之迭代器模式:不暴露内部实现,顺序访问集合

By 来两杯美式
发布于

这是 2020 年 8 月整理的设计模式专题收官篇。迭代器模式的笔记只有一句话定义,本文补全了完整示例。它是 Java 集合框架的地基——你每天都在用 for-each 遍历集合,底层就是迭代器在跑。

基本说明

迭代器模式(Iterator Pattern):提供一种方法,顺序访问一个集合的各个对象,而不暴露该对象的内部实现

客户端 ──> 迭代器(Iterator)──> 集合(Aggregate)
            hasNext() / next()       (内部结构:数组 / 链表 / 哈希表)
       (客户端只跟迭代器打交道,不知道集合内部长什么样)

为什么需要迭代器

痛点:遍历不同结构的集合,方式完全不同:

// 数组:用下标
for (int i = 0; i < array.length; i++) { ... }

// 链表:用指针
while (node != null) { node = node.next; ... }

// 哈希表:要遍历桶
for (Entry e : map.entrySet()) { ... }

问题:客户端要遍历集合,就必须知道集合的底层结构——数组用下标、链表用指针、Hash 用桶。一旦集合结构变了(ArrayList 换 LinkedList),所有遍历代码都要改。

迭代器解法:把”怎么遍历”封装进迭代器,客户端只依赖统一的 hasNext()/next() 接口,集合内部结构对客户端完全透明。

代码实现

手写一个简单的迭代器,遍历自定义的”课程集合”:

/**
 * 描述:自定义集合:课程列表
 */
public class CourseList {
    private Course[] courses = new Course[10];
    private int size = 0;

    public void add(Course course) {
        courses[size++] = course;
    }

    // 返回迭代器,客户端不直接接触数组
    public CourseIterator iterator() {
        return new CourseIteratorImpl(this);
    }

    Course[] getCourses() {
        return courses;
    }

    int getSize() {
        return size;
    }
}

/**
 * 描述:迭代器接口(对应 JDK 的 Iterator)
 */
public interface CourseIterator {
    boolean hasNext();   // 是否还有下一个
    Course next();       // 返回下一个元素
}

/**
 * 描述:迭代器实现:内部持有数组下标游标
 */
public class CourseIteratorImpl implements CourseIterator {
    private CourseList courseList;
    private int position = 0;   // 游标:当前遍历位置

    public CourseIteratorImpl(CourseList courseList) {
        this.courseList = courseList;
    }

    @Override
    public boolean hasNext() {
        return position < courseList.getSize();
    }

    @Override
    public Course next() {
        return courseList.getCourses()[position++];
    }
}

/**
 * 描述:客户端
 */
public class Client {
    public static void main(String[] args) {
        CourseList list = new CourseList();
        list.add(new Course("Java"));
        list.add(new Course("Python"));

        // 客户端只依赖迭代器接口,不知道底层是数组
        CourseIterator iterator = list.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next().getName());
        }
    }
}

三个角色

核心:即使 CourseList 底层把数组换成链表,客户端的遍历代码一行都不用改——hasNext()/next() 接口不变。

JDK 集合框架中的迭代器

Java 集合框架把迭代器模式用得炉火纯青:

集合底层结构迭代方式
ArrayList数组下标递增
LinkedList双向链表指针后移
HashSet哈希表遍历桶内链表
TreeSet红黑树中序遍历

共同点:都实现了 Iterator 接口的 hasNext()/next()/remove()。所以客户端可以用统一的方式遍历所有集合——这正是 for-each 的本质:

// for-each 语法糖,编译后等价于迭代器遍历
for (Course c : courseList) {
    System.out.println(c.getName());
}

迭代器特性

适用场景与优缺点

适用场景

优点

缺点

小结


分享这篇文章:
通过邮件分享这篇文章✓ 链接已复制
查看系列全部文章
  1. 01.软件设计原则:SOLID + KISS / YAGNI / LOD 全景
  2. 02.设计模式之原型模式,及深浅拷贝
  3. 03.设计模式之工厂模式:简单工厂、工厂方法与抽象工厂
  4. 04.设计模式之建造者模式:复杂对象的组装艺术
  5. 05.设计模式之适配器模式:让不兼容的接口协同工作
  6. 06.设计模式之桥接模式:抽象与实现分离,各自独立变化
  7. 07.设计模式之装饰者模式:动态增强,比继承更有弹性
  8. 08.设计模式之代理模式:静态代理与 JDK 动态代理
  9. 09.设计模式之外观模式:统一门面,简化子系统调用
  10. 10.设计模式之享元模式:共享细粒度对象,降低内存占用
  11. 11.设计模式之策略模式:算法家族,自由切换
  12. 12.设计模式之模板方法模式:固定骨架,可变步骤
  13. 13.设计模式之观察者模式:一对多依赖,状态变更自动通知
  14. 14.设计模式之责任链模式:请求逐级传递,动态组合处理者
  15. 15.设计模式之状态模式:状态变,行为变
  16. 16.设计模式之迭代器模式:不暴露内部实现,顺序访问集合

上一篇
T3 Stack 开发规范
下一篇
设计模式之状态模式:状态变,行为变