设计模式之迭代器模式
一、概念
定义:提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需要知道集合对象的底层表示,即:不暴露其内部的结构
- 意图:如果我们的集合元素是用不同方式实现的,有数组、集合或者其他方式。当客户端要遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决。
二、角色职责
- 迭代器模式主要包含以下角色:
- 抽象聚合(Aggregate)角色:定义添加聚合元素以及创建迭代器对象的接口。
- 具体聚合(ConcreteAggregate)角色:声明要遍历的元素容器,实现抽象聚合类,返回一个具体迭代器的实例。
- 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、next() 、remove()等方法。
- 具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。
三、类图
四、案例实现
【例】定义一个可以存储学生对象的容器对象,将遍历该容器的功能交由迭代器实现
类图如下:
- 创建一个学生类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
}
- 定义迭代器接口,声明hasNext、next方法:
public interface StudentIterator {
/**
* 是否还有元素
*
* @return
*/
boolean hasNext();
/**
* 当前元素
*
* @return
*/
Student next();
/**
* 移除当前元素
*/
void remove(Student student);
}
- 定义具体的迭代器类,重写所有的抽象方法:
public class StudentIteratorImpl implements StudentIterator {
/**
* 要迭代的集合
*/
private List<Student> list;
/**
* 当前元素索引
*/
private int position = 0;
public StudentIteratorImpl(List<Student> list) {
this.list = list;
}
@Override
public boolean hasNext() {
return position < list.size();
}
@Override
public Student next() {
Student currentStudent = list.get(position);
position++;
return currentStudent;
}
@Override
public void remove(Student student) {
list.remove(student);
}
}
- 定义抽象容器类,包含添加元素,删除元素,获取迭代器对象的方法:
public interface StudentAggregate {
/**
* 添加元素
*
* @param student
*/
void addStudent(Student student);
/**
* 获取迭代器
*
* @return
*/
StudentIterator getStudentIterator();
}
- 定义具体的容器类,重写所有的方法:
public class StudentAggregateImpl implements StudentAggregate{
private List<Student> list = new ArrayList<>();
@Override
public void addStudent(Student student) {
list.add(student);
}
@Override
public StudentIterator getStudentIterator() {
return new StudentIteratorImpl(list);
}
}
- 测试类
public class Client {
public static void main(String[] args) {
StudentAggregateImpl studentAggregate = new StudentAggregateImpl();
studentAggregate.addStudent(new Student("张三", 20));
studentAggregate.addStudent(new Student("李四", 30));
studentAggregate.addStudent(new Student("王五", 40));
studentAggregate.addStudent(new Student("赵六", 50));
StudentIterator studentIterator = studentAggregate.getStudentIterator();
while (studentIterator.hasNext()) {
Student student = studentIterator.next();
if (student.getAge() >= 50) {
studentIterator.remove(student);
} else {
System.out.println(student);
}
}
}
}
新增数组元素
public class StudentAggregateImpl002 implements StudentAggregate{
private Student[] students = new Student[5];
//保存当前数组的对象个数
int numOfStudents = 0;
@Override
public void addStudent(Student student) {
students[numOfStudents] = student;
numOfStudents++;
}
@Override
public StudentIterator getStudentIterator() {
return new StudentIteratorImpl002(students);
}
}
public class StudentIteratorImpl002 implements StudentIterator {
/**
* 要迭代的数组
*/
private Student[] students;
/**
* 当前元素索引
*/
private int position = 0;
public StudentIteratorImpl002(Student[] students) {
this.students = students;
}
@Override
public boolean hasNext() {
if(position >= students.length || students[position] == null) {
return false;
}else {
return true;
}
}
@Override
public Student next() {
Student currentStudent = students[position];
position++;
return currentStudent;
}
@Override
public void remove(Student student) {
Student[] removeEle = ArrayUtil.removeEle(students, student);
students = removeEle;
}
}
StudentAggregateImpl002 studentAggregate = new StudentAggregateImpl002();
studentAggregate.addStudent(new Student("张三", 20));
studentAggregate.addStudent(new Student("李四", 30));
studentAggregate.addStudent(new Student("王五", 40));
studentAggregate.addStudent(new Student("赵六", 50));
StudentIterator studentIterator = studentAggregate.getStudentIterator();
while (studentIterator.hasNext()) {
Student student = studentIterator.next();
if (student.getAge() >= 50) {
studentIterator.remove(student);
} else {
System.out.println(student);
}
}
五、总结
-
1,优点:
- 它支持以不同的方式遍历一个聚合对象,在同一个聚合对象上可以定义多种遍历方式。在迭代器模式中只需要用一个不同的迭代器来替换原有迭代器即可改变遍历算法,我们也可以自己定义迭代器的子类以支持新的遍历方式。
-
迭代器简化了聚合类。由于引入了迭代器,在原有的聚合对象中不需要再自行提供数据遍历等方法,这样可以简化聚合类的设计。
- 在迭代器模式中,由于引入了抽象层,增加新的聚合类和迭代器类都很方便,无须修改原有代码,满足 “开闭原则” 的要求。
2,缺点:
增加了类的个数,这在一定程度上增加了系统的复杂性。
-
使用场景:
- 当需要为聚合对象提供多种遍历方式时。
-
当需要为遍历不同的聚合结构提供一个统一的接口时。
- 当访问一个聚合对象的内容而无须暴露其内部细节的表示时。