✍ 一个聚合对象,如一个列表(List)或者一个集合(Set),应该提供一种方法来让别人可以访问它的元素,而又不需要暴露它的内部结构。
针对不同的需要,可能还要以不同的方式遍历整个聚合对象
,但是我们并不希望在聚合对象的抽象层接口中充斥着各种不同遍历的操作。
怎样遍历一个聚合对象,又不需要了解聚合对象的内部结构,还能够提供多种不同的遍历方式,这就是迭代器模式所要解决的问题。
在迭代器模式中,提供一个外部的迭代器
来对聚合对象进行访问和遍历,迭代器定义了一个访问该聚合元素的接口,并且可以跟踪当前遍历的元素,了解哪些元素已经遍历过而哪些没有。
有了迭代器模式,我们会发现对一个复杂的聚合对象的操作会变得如此简单
迭代器模式( Iterator pattern)定义如下:提供一种方法来访问聚合对象
,而不用暴露这个对象的内部表示
,其别名为游标( Cursor)
。迭代器模式是一种对象行为型
模式
迭代器模式包含如下角色:
- Iterator:抽象迭代器:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。
- Concretelterator:具体迭代器:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。
- Aggregate:抽象聚合类:定义存储、添加、删除聚合对象以及创建迭代器对象的接口
- Concreteaggregate:具体聚合类:实现抽象聚合类,返回一个具体迭代器的实例。
✍ 演示一下:
首先创建一个课程类
//课程类
public class Course {
private String name;
public Course(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
课程的相关信息接口 与迭代器绑定(Aggregate:抽象聚合类)
public interface CourseAggregate {
void addCourse(Course course); //增加课程
void removeCourse(Course course); //删除课程
CourseIterator getCourseIterator(); //获取这个课程的迭代器
}
实现上述接口的类(Concreteaggregate:具体聚合类)
import java.util.ArrayList;
import java.util.List;
public class CourseAggregateImpl implements CourseAggregate {
private List courseList;
public CourseAggregateImpl() {
this.courseList = new ArrayList();
}
@Override
public void addCourse(Course course) {
courseList.add(course);
}
@Override
public void removeCourse(Course course) {
courseList.remove(course);
}
@Override
public CourseIterator getCourseIterator() {
return new CourseIteratorImpl(courseList);
}
}
课程的迭代器(Iterator:抽象迭代器)
public interface CourseIterator {
Course nextCourse(); //获取下一个课程
boolean isLastCourse(); //判断课程是否是最后的
}
实现此迭代器的类(Concretelterator:具体迭代器)
import java.util.List;
public class CourseIteratorImpl implements CourseIterator {
private List courseList;
private int position;
private Course course;
public CourseIteratorImpl(List courseList){
this.courseList=courseList;
}
@Override
public Course nextCourse() {
System.out.println("返回课程,位置是: "+position);
course=(Course)courseList.get(position);
position++;
return course;
}
@Override
public boolean isLastCourse(){
if(position< courseList.size()){
return false;
}
return true;
}
}
类图:
测试类
public class Test {
public static void main(String[] args) {
Course course1 = new Course("Java设计模式");
Course course2 = new Course("Java编程思想");
Course course3 = new Course("Java核心技术卷1");
Course course4 = new Course("Java核心技术卷2");
Course course5 = new Course("Java网络编程");
Course course6 = new Course("Git三剑客");
CourseAggregate courseAggregate = new CourseAggregateImpl();
courseAggregate.addCourse(course1);
courseAggregate.addCourse(course2);
courseAggregate.addCourse(course3);
courseAggregate.addCourse(course4);
courseAggregate.addCourse(course5);
courseAggregate.addCourse(course6);
System.out.println("-----课程列表-----");
printCourses(courseAggregate);
courseAggregate.removeCourse(course4);
courseAggregate.removeCourse(course5);
System.out.println("-----删除操作之后的课程列表-----");
printCourses(courseAggregate);
}
public static void printCourses(CourseAggregate courseAggregate){
CourseIterator courseIterator= courseAggregate.getCourseIterator();
while(!courseIterator.isLastCourse()){
Course course=courseIterator.nextCourse();
System.out.println(course.getName());
}
}
}
结果:
✍ 模式分析
聚合是一个管理和组织数据对象
的数据结构。聚合对象主要拥有两个职责:一是存储内部数据
;二是遍历内部数据
。存储数据
是聚合对象最基本的职责。将遍历聚合对象中数据的行为提取出来,封装到一个迭代器中
,通过专门的迭代器来遍历聚合对象的内部数据,这就是迭代器模式的本质。迭代器模式是“单一职责原则”
的完美体现。
在迭代器模式中应用了工厂方法模式
,聚合类充当工厂类
,而迭代器充当产品类
,由于定义了抽象层,系统的扩展性很好,在客户端可以针对抽象聚合类和抽象迭代器进行编程。
由于很多编程语言的类库都已经实现了迭代器模式,因此在实际使用中我们很少自定义迭代器,只需要直接使用Java、C#等语言中已定义好的迭代器即可,迭代器已经成为我们操作聚合对象的基本工具之一
✍ 模式优缺点
迭代器模式的优点
- 它支持以不同的方式遍历一个聚合对象。
- 迭代器简化了聚合类。
- 在同一个聚合上可以有多个遍历。
- 在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码,满足
“开闭原则”
的要求。
迭代器模式的缺点
- 由于迭代器模式将存储数据和遍历数据的职责分离,
增加新的聚合类需要对应增加新的迭代器类
,类的个数成对增加
,这在一定程度上增加了系统的复杂性。
✍ 在以下情况下可以使用迭代器模式:
- 访问一个聚合对象的内容而无须暴露它的内部表示。
- 需要为聚合对象提供多种遍历方式。
- 为遍历不同的聚合结构提供一个统一的接口。
✍ 模式应用:
Collection是所有Java聚合类的根接口,在JDK类库中, Collection的 iterator0方法返回一个java.util.Iterator类型的对象,而其子接口javautil. List的 listiterator方法返回一个java.util. ListIterator类型的对象, Listiterator是Iterator的子类
。它们构成了Java语言对迭代器模式的支持,Java语言的 java util.Iterator接口就是迭代器模式的应用。
Java迭代器在JDK中, Iterator接口具有如下3个基本方法:
(1) Object next():通过反复调用 next()方法可以逐个访问聚合中的元素
(2) boolean hasNext(): hasNext()方法用于判断聚合对象中是否还存在下一个元素,为了不抛出异常,必须在调用next()之前先调用 hasNext() 。如果迭代对象仍然拥有可供访问的元素,那么 hasNext() 返回true
(3) void remove:用于删除上次调用 next() 时所返回的元素。
Java迭代器Java迭代器可以理解为它工作在聚合对象的各个元素之间,每调用次next()方法,迭代器便越过下个元素,并且返回它刚越过的那个元素的地址引用。但是,它也有一些限制,如某些迭代器只能单向移动。在使用迭代器时,访问某个元素的唯一方法就是调用next()