从零开始学习Java设计模式 | 行为型模式篇:迭代器模式
Posted 李阿昀
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从零开始学习Java设计模式 | 行为型模式篇:迭代器模式相关的知识,希望对你有一定的参考价值。
在本讲,我们来学习一下行为型模式里面的第八个设计模式,即迭代器模式。
概述
相信大家对于迭代器并不会感到陌生,因为平时我们使用的还是比较多的,注意,在这儿我说的是使用。
在开发过程中我们会经常去遍历单列集合,既然要遍历,那么我们就可以选择使用迭代器去遍历了,而迭代器底层使用的就是迭代器模式。那么到底什么是迭代器模式呢?下面我们就来看看它的概念。
提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。
看完迭代器模式的概念,相信大家一时半会还无法理解,不过没关系,下面我给大家解释一下。
迭代器模式是说提供一个对象来顺序访问聚合对象中的一系列数据,而这其实指的就是遍历,这句话中的聚合对象,大家可以理解成是集合(或者容器),自然地,聚合对象中的一系列数据就是指该集合(或者容器)里面存储的元素了。那么这样遍历有什么作用呢?不暴露聚合对象的内部表示,也就是说我们并不需要去关注集合(或者容器)内部是如何去存储元素的。
以上就是迭代器模式的概念,其实说到底,就是提供了一种遍历的方式。
理解了迭代器模式的概念之后,接下来,我们就来看看迭代器模式的结构,也就是它里面所拥有的角色。
结构
迭代器模式主要包含以下角色:
- 抽象聚合(Aggregate)角色:定义存储、添加、删除聚合元素(聚合元素,你可以理解成是容器里面存储的数据)以及创建迭代器对象的接口。注意了,该角色只是提供了这么一些抽象方法,而这些抽象方法是要由子类来实现的,这个子类就是具体聚合角色类。
- 具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。
- 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含hasNext()、next()等方法,hasNext()方法是用于判断是否还有元素的,而next()方法是用于获取下一个元素的。
- 具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。
下面我会通过一个具体的案例来让大家再深入认识一下以上迭代器模式的四个角色。
迭代器模式案例
接下来,按照惯例我们通过一个案例来让大家再去理解一下迭代器模式的概念,以及它里面所包含的角色。这个案例就是定义一个可以存储学生对象的容器对象,并将遍历该容器的功能交由迭代器实现。
分析
在该案例中,我们需要定义一个可以存储学生对象的容器对象,其实说到底就是让我们自定义一个集合,而这个集合里面存储的是学生对象。然后再将遍历该容器的功能交由迭代器实现,而这正好就要用到迭代器模式。
接下来,我们来看一下下面的这张类图。
可以看到,以上类图的最下面有一个学生类,即Student,该类的对象就是容器里面要存储的元素。至于该类里面的属性和方法,你想定义什么都行(这不,该类我们是像上面类图那样设计的),因为该类的对象就是往容器里面去存的,也就是说容器里面只能存储学生对象。
然后,我们来看一下以上类图的左侧部分。可以看到,上面有一个接口,名称是StudentIterator,翻译过来就是学生迭代器,很明显,该接口充当的就是迭代器模式里面的抽象迭代器角色。而且,该接口里面定义了两个规范方法,分别是:
- boolean hasNext():判断是否还有元素。
- Student next():获取下一个元素。注意,该方法的返回类型是Student类型,并不是特别通用,因为该方法只能获取学生对象。如果你想让该方法更通用,即能获取其他任意类型的对象,那么不妨用一下泛型。当然了,这儿我并没有这样去做啊,所以就不做过多的说明了。
再来看下面,可以看到下面有一个类,名称是StudentIteratorImpl,很明显,该类就是以上抽象迭代器接口的子实现类,那么它充当的就是迭代器模式里面的具体迭代器角色。而且,该类里面声明了两个成员变量,一个是List<Student>
类型的成员变量,很显然,该成员变量里面存储的是学生对象。为什么要在该类里面声明这么一个类型的成员变量呢?这是因为到时候我们定义的容器里面存储的就是学生对象,当然了,使用的也是List集合来存储学生对象。此外,还有一个int类型的成员变量,该成员变量是用来记录遍历时的位置的。
大家也能看到,在该具体迭代器类中,我们还提供了一个有参的构造方法,它就是用于给List<Student>
类型的成员变量赋值的。除此之外,该类还重写了父接口里面的两个抽象方法。
最后,我们来看一下以上类图的右侧部分。可以看到,上面有一个接口,名称是StudentAggregate,该接口充当的是迭代器模式里面的抽象聚合角色。而且,该接口里面定义了一些规范方法,分别是:
- void addStudent(Student student):往聚合对象里面添加学生对象。
- void removeStudent(Student student):从聚合对象里面删除学生对象。
- StudentIterator getStudentIterator():获取学生迭代器对象。
注意,以上只是一些规范方法,具体应该由具体的子类来实现。
再来看下面,可以看到下面有一个类,名称是StudentAggregateImpl,很明显,该类就是以上抽象聚合接口的子实现类,那么它充当的就是迭代器模式里面的具体聚合角色。而且,从上还可以看到,该类的成员位置处定义了一个List集合,而集合里面存储的正是学生对象。当然,我们现在是在设计,肯定是知道这个聚合对象里面的具体的实现的,然而,对于使用者来说,他到时候就不用去关注于底层是如何实现的了。除此之外,该类还重写了父接口里面的三个抽象方法。
至此,对于以上类图中所涉及到的类和接口,我们就一一分析清楚了。至于类和类,以及类和接口之间的关系,大家看上图便知道了。
实现
首先,打开咱们的maven工程,并在com.meimeixia.pattern包下新建一个子包,即iterator,也即实现以上案例的具体代码我们是放在了该包下。
然后,创建学生类,这里我们就命名为Student了。
package com.meimeixia.pattern.iterator;
/**
* 学生类
* @author liayun
* @create 2021-09-18 10:17
*/
public class Student {
private String name; // 姓名
private String num; // 学号
public Student() {
}
public Student(String name, String num) {
this.name = name;
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNum() {
return num;
}
public void setNum(String num) {
this.num = num;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\\'' +
", num='" + num + '\\'' +
'}';
}
}
接着,创建迭代器接口,这里我们不妨就命名为StudentIterator。
package com.meimeixia.pattern.iterator;
/**
* 抽象迭代器角色接口
* @author liayun
* @create 2021-09-18 10:22
*/
public interface StudentIterator {
/**
* 判断是否还有元素
*/
boolean hasNext();
/**
* 获取下一个元素
*
* 因为我们这儿是专门用来遍历学生对象的,所以该方法的返回值类型我们就设置为了Student。
* 当然,如果你想让该方法更通用,那么不妨使用一下泛型,只是在这里我并没有这样去做!
*/
Student next();
}
紧接着,创建具体迭代器类,这里我们不妨就命名为StudentIteratorImpl。
以上是关于从零开始学习Java设计模式 | 行为型模式篇:迭代器模式的主要内容,如果未能解决你的问题,请参考以下文章