23种设计模式之迭代器模式
参考资料
- Java设计模式:23种设计模式全面解析(超级详细)
- 韩顺平老师的Java设计模式(图解+框架源码剖析)
- 秦小波老师的《设计模式之禅》
下文如有错漏之处,敬请指正
一、简介
定义
迭代器模式提供一种方法能访问容器对象中各个元素,而不暴露该对象的内部结构。
迭代器是为容器服务的,能容纳对象的所有类型都可以称之为容器,例如Collection集合类型、List类型、Set类型等,迭代器模式就是为解决遍历这些容器中的元素而诞生的。
特点
- 迭代器模式是一种行为型模式
通用类图
迭代器模式的主要角色:
-
Aggregate
抽象容器角色
定义添加、删除元素以及创建迭代器对象的接口createIterator()。
-
ConcreteAggregate
具体容器角色
实现抽象容器接口定义的方法,返回一个具体迭代器的实例。
-
Iterator
抽象迭代器角色
定义访问和遍历容器元素的接口,通常包含 hasNext()是否已经访问到底部、first()获得第一个元素、next() 访问下一个元素方法。
-
Concretelterator
具体迭代器角色
实现抽象迭代器接口中所定义的方法,完成对容器对象元素的遍历。
优点
-
访问一个容器对象的元素而无须暴露它的内部结构。
-
支持以不同方式遍历同一个容器对象,甚至可以自定义迭代器的子类以支持新的遍历。
-
增加新的容器类和迭代器类都很方便,符合开闭原则。
应用场景
- 当需要为容器对象提供多种遍历方式时。
- 当需要为遍历不同的容器对象提供一个统一的接口时。
- 当访问一个容器对象的元素而无须暴露其内部细节时。
二、迭代器模式
需求:
一个公司有多个部门,每个部门有多个员工,现在部门用集合类型进行存储,部门员工用数组进行存储,使用迭代器模式访问聚合公司部门和部门员工的数据。
部门类:
package iterator;
public class Department {
private String deptName;
public Department(String deptName) {
this.deptName = deptName;
}
@Override
public String toString() {
return "Department{" +
"deptName='" + deptName + '\'' +
'}';
}
}
员工类:
package iterator;
public class Staff {
private Department department;
private String name;
public void setDepartment(Department department) {
this.department = department;
}
public Staff(String name) {
this.name = name;
}
@Override
public String toString() {
return "Staff{" +
"department=" + department +
", name='" + name + '\'' +
'}';
}
}
抽象容器角色:
package iterator;
public interface Aggregate {
public void add(Object obj);
public void remove(Object obj);
public Iterator getIterator();
}
具体容器角色:
package iterator;
import java.util.ArrayList;
import java.util.List;
public class CompanyAggregate implements Aggregate {
List<Object> departments=new ArrayList<>();
@Override
public void add(Object obj) {
departments.add(obj);
}
@Override
public void remove(Object obj) {
departments.remove(obj);
}
@Override
public Iterator getIterator() {
return new CompanyIterator(departments);
}
}
package iterator;
import java.util.LinkedList;
import java.util.Queue;
public class DepartmentAggregate implements Aggregate {
private Object[] staffs=new Staff[100];
private int index=-1;
@Override
public void add(Object obj) {
staffs[++index]=obj;
}
@Override
public void remove(Object obj) {
int i=-1;
for (Object staff : staffs) {
++i;
if (staff.equals(obj)) {
for(;i<index;++i){
staffs[i]=staffs[i+1];
}
--index;
return;
}
}
}
@Override
public Iterator getIterator() {
return new DepartmentIterator(staffs,index);
}
}
抽象迭代器:
package iterator;
public interface Iterator {
// 访问第一个元素
Object first();
// 遍历到下一个元素
Object next();
// 是否已经遍历到尾部
boolean hasNext();
}
具体迭代器:
package iterator;
import java.util.List;
public class CompanyIterator implements Iterator {
private List<Object> departments=null;
private int index=-1;
public CompanyIterator(List<Object> departments) {
this.departments = departments;
}
@Override
public Object first() {
Object obj=departments.get(0);;
return obj;
}
@Override
public Object next() {
Object obj=null;
if(this.hasNext())
{
obj=departments.get(++index);
}
return obj;
}
@Override
public boolean hasNext() {
if(index<departments.size()-1)
{
return true;
}
else
{
return false;
}
}
}
package iterator;
import java.util.List;
public class DepartmentIterator implements Iterator {
private Object[] staffs=null;
private int index=-1;
private int size;
public DepartmentIterator(Object[] staffs,int size) {
this.staffs = staffs;
this.size=size;
}
@Override
public Object first() {
Object obj=staffs[0];
return obj;
}
@Override
public Object next() {
Object obj=null;
if(this.hasNext())
{
obj=staffs[++index];
}
return obj;
}
@Override
public boolean hasNext() {
if(index<size)
{
return true;
}
else
{
return false;
}
}
}
Client:
package iterator;
public class Client {
public static void main(String[] args) {
// 模拟公司添加部门
Department d1 = new Department("技术部");
Department d2 = new Department("营运部");
Department d3 = new Department("公关部");
Aggregate container = new CompanyAggregate();
// 将部门加入到公司容器
container.add(d1);
container.add(d2);
container.add(d3);
// 获取公司部门的迭代器
Iterator containerIterator = container.getIterator();
// 打印所有部门的信息
while (containerIterator.hasNext()) {
System.out.println(containerIterator.next());
}
System.out.println("==========================");
// 模拟部门添加员工
Staff s1 = new Staff("张三");
s1.setDepartment(d1);
Staff s2 = new Staff("李四");
s2.setDepartment(d2);
Staff s3 = new Staff("王五");
s3.setDepartment(d3);
container = new DepartmentAggregate();
// 将员工加入到部门容器
container.add(s1);
container.add(s2);
container.add(s3);
// 从部门容器中删除员工
container.remove(s1);
// 获取部门员工的迭代器
containerIterator = container.getIterator();
// 打印第一个员工
System.out.println("打印第一个员工:" + containerIterator.first());
System.out.println("==========================");
// 打印所有员工
while (containerIterator.hasNext()) {
System.out.println(containerIterator.next());
}
/**
* 输出结果:
* Department{deptName='技术部'}
* Department{deptName='营运部'}
* Department{deptName='公关部'}
* ==========================
* 打印第一个员工:Staff{department=Department{deptName='营运部'}, name='李四'}
* ==========================
* Staff{department=Department{deptName='营运部'}, name='李四'}
* Staff{department=Department{deptName='公关部'}, name='王五'}
*
*/
}
}
当增加一个新的实体对象时(如合作企业),只需要增加对应的具体容器类和迭代器类,便可以通过对应的迭代器访问容器对象的内部数据。
三、总结
- 迭代器模式是通过将容器对象的遍历行为分离出来,抽象成迭代器类来实现,其目的是在不暴露容器对象的内部结构的情况下,让外部代码透明地访问聚合的内部数据。
- 迭代器模式目前已经是一个没落的模式,因为从JDK1.2版本开始增加java.util.Iterator这个接口,并逐步把Iterator应用到各个聚集类 (Collection)中,直接使用Collection下的实现类(Collection,List,Queue,Set等)就可以完美地解决问题。