1. 模式定义

  • 1)迭代器模式(lterator Pattern)是常用的设计模式,属于行为型模式
  • 2)如果我们的集合元素是用不同方式实现的,有数组、集合或者其他方式。当客户端要遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决
  • 3)迭代器模式,提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需要知道集合对象的底层表示,即:不暴露其内部的结构
    image.png

2. 模式结构

2.1. 模式角色

  • 抽象聚合(Aggregate)角色:定义存储、添加、删除聚合元素以及创建迭代器对象的接口。将客户端和具体的聚合解耦
  • 具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例
  • 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、next() 等方法。
  • 具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。

2.2. UML

image.png

2.3. 实现逻辑

  1. 在具体聚合类中,具体聚合类提供返回具体迭代器类的方法,在该方法中new一个与之对应的迭代器来并返回。具体聚合类与具体迭代器类绑定,一一对应
  2. 与1中代码一样位置一样,在new具体迭代器类的时候,将需要迭代的集合或者数组传入该迭代器的构造函数%%
    1605-🏡⭐️◼️迭代器模式的核心逻辑是什么?1. 具体聚合类需提供一个方法,负责返回一个具体迭代器类,在该方法中绑定了该具体聚合类对应的具体迭代器类,通过这种绑定关系,避免大量ifelse判断。类似的模式还有模板方法模式、适配器模式。2. 在该方法中具体聚合类还将自己维护的数据集合提供给具体迭代器的构造函数作为入参◼️⭐️-point-202301261605%%

3. 案例分析

3.1. 迭代器完成学校院系结构展示✅

3.1.1. UML

image.png

3.1.2. 实现逻辑⭐️🔴

3.1.2.1. 具体聚合类与具体迭代器类绑定 1到1模型

具体聚合类与具体迭代器类绑定配对,一一对应的方式,与适配器模式(HandlerAdapter)、工厂方法模式有点相似
image.png

HandlerAdapter设计模式-8、适配器模式
image.png

工厂方法模式:[[内功心法专题-设计模式-4、工厂模式#3 3 2 UML⭐️🔴]]

%%
1436-🏡⭐️◼️1对1设计模式有哪些?🔜📝❔适配器模式、模板方法模式、迭代器模式◼️⭐️-point-202301271436%%

3.1.2.2. 具体聚合类传参给具体迭代器类

image.png

3.1.2.3. 利用多态原理获取产品对应迭代器

image.png

3.1.3. 示例代码

[[pages/002-schdule/001-Arch/001-Subject/013-DemoCode/DesignPattern/src/com/atguigu/iterator/College.java]]

3.2. 存储学生对象

3.2.1. UML

3.2.2. 实现逻辑

image.png

  1. 具体聚合类与具体迭代器类绑定,一一对应
  2. 具体聚合类传参给具体迭代器类,构造导入需要迭代的集合或者数组

3.2.3. 示例代码

[[pages/002-schdule/001-Arch/001-Subject/013-DemoCode/design_patterns/src/main/java/com/itheima/pattern/iterator/StudentAggregate.java]]

4. 适用场景⭐️🔴

  • 1对多:当需要为聚合对象提供多种遍历方式时。
  • 多对1:当需要为遍历不同的聚合结构提供一个统一的接口时。
  • 当访问一个聚合对象的内容而无须暴露其内部细节的表示时。

5. 优缺点⭐️🔴

1. 优点

  1. 提供一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以遍历对象,同时可以隐藏聚合的内部结构。
  2. 便于新增或者更改遍历算法:新增一种具体迭代器,然后修改具体聚合类返回迭代器的地方即可
  3. 迭代器简化了聚合类。由于引入了迭代器,在原有的聚合对象中不需要再提供数据遍历等方法,这样可以简化聚合类的设计
  4. 在迭代器模式中,由于引入了抽象层,增加新的聚合类和迭代器类都很方便,无须修改原有代码,满足 “开闭原则” 的要求
  5. 提供了一种设计思想,就是一个类应该只有一个引起变化的原因(单一责任原则)。在聚合类中,我们把迭代器分开,就是要把管理对象集合和遍历对象集合的责任分开,这样一来集合改变的话,只影响到聚合对象。而如果遍历方式改变的话,只影响到了迭代器

2. 缺点

增加了类的个数,每个聚合对象都要一个迭代器,会生成多个迭代器不好管理类这在一定程度上增加了系统的复杂性。

6. JDK源码分析

6.1. ArrayList的iterator()

1
2
3
4
5
List<String> list = new ArrayList<>();
Iterator<String> iterator = list.iterator(); //list.iterator()方法返回的肯定是Iterator接口的子实现类对象
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
  • List (聚合接口):定义了iterator()方法,返回一个迭代器接口对象
  • ArrayList (具体聚合实现类):实现了抽象聚合接口List的iterator()方法
  • Iterator (迭代器接口):由系统提供,定义了hasNext()next()等方法
  • Itr (具体迭代器实现类):ArrayList.iterator()方法返回值,是ArrayList的内部类,实现了 Iterator接口的hasNext()next()等方法

迭代器模式提供了一个不同集合类型(如ArrayListLinkedList等)的统一遍历解决方案

image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {

public Iterator<E> iterator() {
return new Itr();
}

private class Itr implements Iterator<E> {
int cursor; // 下一个要返回元素的索引
int lastRet = -1; // 上一个返回元素的索引
int expectedModCount = modCount;

Itr() {}

//判断是否还有元素
public boolean hasNext() {
return cursor != size;
}

//获取下一个元素
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
...
}

这部分代码还是比较简单,大致就是在 iterator 方法中返回了一个实例化的 Iterator 对象。Itr是一个内部类,它实现了 Iterator 接口并重写了其中的抽象方法。

注意:

当我们在使用JAVA开发的时候,想使用迭代器模式的话,只要让我们自己定义的容器类实现java.util.Iterable并实现其中的iterator()方法使其返回一个 java.util.Iterator 的实现类就可以了。

7. 实战经验

8. 参考与感谢

设计模式-2、设计模式及设计原则