设计模式实战-迭代器模式,最常用的设计模式之一
迭代器模式(Iterator Pattern)又称为游标(Cursor)模式,是最常被使用的几个模式之一,被广泛地应用到 Java 的 API 中。例如,Java 的集合(Collection)框架中,就广泛使用迭代器来遍历集合中的元素。
1、定义
迭代器模式的英文定义如下:
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
意思是:提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。
迭代器是为容器服务的,容器是指用来容纳其他对象的对象,例如,Collection 集合类型、Set 类等。
2、组成角色
迭代器模式有以下 4 个角色:
- 抽象迭代器(Iterator)角色:该角色负责定义访问和遍历元素的接口;
- 具体迭代器(Concrete Iterator)角色:该角色实现 Iterator 接口,完成容器元素的遍历;
- 抽象聚集(Aggregate)角色:该角色提供创建迭代器角色的接口;
- 具体聚集(Concrete Aggregate)角色:该角色实现抽象聚集接口,创建出容纳迭代器的对象。
角色之间的关系,如下图所示:
3、迭代器模式代码实现
3.1 抽象迭代器
interface Iterator {
public Object next();
public boolean hasNext();
}
3.2 具体迭代器
class ConcreteIterator implements Iterator {
private ConcreteAggregate aggregate;
private int index;
private int size;
public ConcreteIterator(ConcreteAggregate aggregate) {
this.aggregate = aggregate;
this.index = 0;
this.size = aggregate.size();
}
// 是否有下一个元素
@Override
public boolean hasNext() {
return index < size;
}
// 返回下一个元素
@Override
public Object next() {
if (index < size) {
return aggregate.getElement(index++);
}
return null;
}
}
3.3 抽象聚集
interface Aggregate {
public void add(Object obj);
public Iterator createIterator();
}
3.4 具体聚集
class ConcreteAggregate implements Aggregate {
// 私有存储容器
private Vector vector = new Vector();
// 添加元素
@Override
public void add(Object obj) {
this.vector.add(obj);
}
// 根据下标获取元素
public Object getElement(int index) {
return vector.get(index);
}
// 获取集合长度
public int size() {
return vector.size();
}
// 创建迭代器
@Override
public Iterator createIterator() {
return new ConcreteIterator(this);
}
}
3.5 客户端
public class Client {
public static void main(String[] args) {
// 定义聚族对象
Aggregate aggregate = new ConcreteAggregate();
aggregate.add("Java");
aggregate.add("MySQL");
aggregate.add("Spring");
// 遍历
Iterator iterator = aggregate.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
程序执行结果:
Java MySQL Spring
4、优缺点
迭代器模式的优点:
- 迭代器模式将数据存储和数据遍历的职责进行分离;
- 迭代器模式简化了遍历容器元素的操作;
- 迭代器模式使不同的容器,具备一个统一的遍历接口;
- 迭代器模式封装了遍历算法,使算法独立于聚集角色,调用者无须知道聚集对象的类型,即使聚集对象的类型发生变化,也不会影响遍历过程。
迭代器模式的缺点:
由于迭代器模式将数据存储和数据遍历的职责进行分离,如果增加新的聚合类,同时需要增加与之相对应的迭代器类,这使得类的个数会成对增加,在某种程度上来说增加了系统的复杂性。
5、应用场景
迭代器的应用很广泛,已经发展成为程序开发中最基础的工具类了。在 Java 语言中,从 JDK 1.2 开始,增加了 java.util.Iterator 接口,并将 Iterator 应用到各个聚集类(Collection)中,如 ArrayList、Vector、Stack、HashSet 等集合类都实现了 iterator() 方法,返回一个迭代器 Iterator,用于对集合中的元素进行遍历。这使我们在项目中无须在独立地写迭代器,直接使用即可,这样既轻松又便捷。
注意:要尽可能地使用编程语言自身提供的迭代器,而非自己写的迭代器。
6、使用实例
下面将会使用 Java API 提供的迭代器模式,演示迭代器的具体使用。
public class Lesson19 {
public static void main(String[] args) {
// 调用迭代器应用示例
new IteratorUseDemo().doIterator();
}
}
/**
* 迭代器应用——演示示例
*/
class IteratorUseDemo {
void doIterator() {
// 定义 Vector 集合
Vector vector = new Vector();
vector.add("Vector 1");
vector.add("Vector 2");
vector.add("Vector 3");
// 定义 ArrayList 集合
ArrayList list = new ArrayList();
list.add("ArrayList 1");
list.add("ArrayList 2");
list.add("ArrayList 3");
// 使用迭代器循环 Vector
java.util.Iterator vIterator = vector.iterator();
while (vIterator.hasNext()) {
System.out.println(vIterator.next());
}
// 使用迭代器循环 ArrayList
java.util.Iterator lIterator = list.iterator();
while (lIterator.hasNext()) {
System.out.println(lIterator.next());
}
}
}
程序执行结果:
Vector 1 Vector 2 Vector 3 ArrayList 1 ArrayList 2 ArrayList 3
从上面示例可以看出,集合都可以通过 iterator() 方法,获得统一的迭代器对象 java.util.Iterator,然后进行循环遍历。
7、总结
迭代器模式是最常用的设计模式之一,已经被广泛应用到 Java 的 API 中,比如在 Java 的集合中,使用 iterator() 方法就可以获得统一的迭代器对象 java.util.Iterator,使用这个对象就可以很方便地实现集合的遍历功能。迭代器包含四个角色(抽象迭代器、具体迭代器、抽象聚集和具体聚集)和两个重要的方法:hasNext() 方法用来判断是否还有下一个未遍历的元素,next() 方法用来获取此次遍历的对象。要注意的是,如果编程语言中已经提供了内置的迭代器,并且能满足现有需求的情况下,开发者就不必自己再写迭代器了
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Kubeflow Pipeline - 构建一个机器学习 Workflow
- Git 如何压缩 commit
- How go build works
- 网状Meta分析之R语言‘gemtc’包实战(3)
- 关于 K8S API Resources: Group 和 Version 该怎么写
- ZooKeeper 的应用场景
- 在 K8S 部署一个 Spark History Server - 篇3
- Go 学习笔记-1
- Tensorflow-gpu 运行在 cpu 母机的问题
- R语言入门之散点图
- Python函数(一)
- Spark on Kubernetes 动态资源分配
- R语言入门之偏度(skewness)与峰度(kurtosis)
- Spark Operator 是如何提交 Spark 作业
- R语言进阶之聚类分析