迭代器模式(Iterator Pattern)
在软件开发时,经常需要使用聚合对象来存储一系列数据,聚合对象拥有两个职责:
一是存储数据;二是遍历数据,前者是聚合对象的基本职责,而后者既是可变化的又是可分离的,因此可将遍历数据的行为从聚合对象中分离出来,封装在一个迭代器对象中;这可简化聚合对象的设计,符合单一职责的原则.
1. 定义: 提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示;
2. 迭代器模式中的角色
1) Iterator(抽象迭代器): 定义了访问和遍历元素的接口,声明了用于遍历数据元素的方法
2) ConcreteIterator(具体迭代器): 实现了抽象迭代器接口,完成了对聚合对象的遍历,通过游标来记录在聚合对象中所处的当前位置,在具体实现时,游标通常是一个表示位置的非负整数;
3) Aggregate(抽象聚合类): 它用于存储和管理元素对象,声明一个createIterator()方法用于创建一个迭代器对象,充当抽象迭代器工厂角色
4) ConcreteAggregate(具体聚合类): 实现抽象聚合类声明的createIterator()方法,该方法返回一个与该具体聚合类对应的具体迭代器实例
若需要增加一个新的聚合类,并提供不同于商品数据聚合类的正向遍历和逆向遍历操作,只需增加一哥新的聚合子类和一个新的具体迭代器类即可,源代码无须修改,符合开闭原则
3. 案例
1) 解决方案
2) 代码实现
package com.zach.pattern.iterator;
/***
*抽象迭代器接口
* @author Zach
*
*/
public interface AbstractIterator {
public void next(); //移至下一个元素
public boolean isLast(); //判断是否为最后一个元素
public void previous(); //移至上一个元素
public boolean isFirst(); //判断是否为第一个元素
public Object getNextItem(); //获取下一个元素
public Object getPreviousItem(); //获取上一个元素
}
package com.zach.pattern.iterator;
import java.util.ArrayList;
import java.util.List;
/**
* 抽象聚合类
* @author Zach
*
*/
public abstract class AbstractObjectList {
protected List<Object> list = new ArrayList<>();
public AbstractObjectList(List<Object> list) {
super();
this.list = list;
}
public void addObject(Object obj) {
this.list.add(obj);
}
public void removeObject(Object obj) {
this.list.remove(obj);
}
public List<Object> getObjects() {
return this.list;
}
//声明抽象迭代器对象的工厂方法
public abstract AbstractIterator createrator();
}
package com.zach.pattern.iterator;
import java.util.List;
/**
* 抽象迭代器
* @author Zach
*
*/
public class ProductIterator implements AbstractIterator {
private ProductList productList; //维持对一个具体聚合类的引用
private List<Object> products;
private int cursor1; //定义一个游标,用于记录正向遍历的位置
private int cursor2; //定义一个逆向的游标,记录逆向遍历的位置
public ProductIterator(ProductList list) {
this.productList = list;
this.products = list.getObjects();
cursor1 = 0;
cursor2 = products.size()-1;
}
@Override
public void next() {
if(cursor1<products.size()) {
cursor1++;
}
}
@Override
public boolean isLast() {
return (cursor1==products.size());
}
@Override
public void previous() {
if(cursor2>-1){
cursor2--;
}
}
@Override
public boolean isFirst() {
// TODO Auto-generated method stub
return (cursor2==-1);
}
@Override
public Object getNextItem() {
// TODO Auto-generated method stub
return products.get(cursor1);
}
@Override
public Object getPreviousItem() {
return products.get(cursor2);
}
}
package com.zach.pattern.iterator;
import java.util.List;
/**
* 具体聚合类
* @author Zach
*
*/
public class ProductList extends AbstractObjectList {
public ProductList(List<Object> list) {
super(list);
// TODO Auto-generated constructor stub
}
@Override
public AbstractIterator createrator() {
// TODO Auto-generated method stub
return new ProductIterator(this);
}
}
package com.zach.pattern.iterator;
import java.util.ArrayList;
import java.util.List;
/**
* 客户端
* @author Zach
*
*/
public class Client {
public static void main(String[] args) {
List<Object> products = new ArrayList<Object>();
products.add("倚天剑");
products.add("屠龙刀");
products.add("断肠草");
products.add("葵花宝典");
products.add("易经经");
//创建聚合对象
AbstractObjectList list = new ProductList(products);
//创建迭代器对象
AbstractIterator iterator = list.createrator();
System.out.println("正向遍历: ");
while(!iterator.isLast()) {
System.out.println(iterator.getNextItem());
iterator.next();
}
System.out.println("===========================");
System.out.println("逆向遍历: ");
while(!iterator.isFirst()){
System.out.println(iterator.getPreviousItem());
iterator.previous();
}
}
}
运行结果
正向遍历:
倚天剑
屠龙刀
断肠草
葵花宝典
易经经
===========================
逆向遍历:
易经经
葵花宝典
断肠草
屠龙刀
倚天剑
若需要为ProductList类更换一个迭代器,只需要增加一个新的迭代器类子类即可;但如果要在迭代器中增加新的方法,则需要修改抽象迭代器源代码,这将违背开闭原则;
4. 使用内部类实现迭代器
在迭代器的模式图中,具体迭代器和具体聚合类之间存在双重关系,在具体迭代器中需要维持一个对具体聚合对象的引用,该关联关系的目的是以便迭代器能够对这些数据进行遍历操作;除了使用关联关系,还可以将迭代器类设计为聚合类的内部类,达到遍历聚合对象的数据的目的,JDK中迭代器类就是通过这种方式实现的
5. 迭代器模式总结
1. 主要优点:
1) 支持以不同的方式遍历一个聚合对象,在同一个聚合对象上可以定义多种遍历方式,只需更换不同的迭代器即可
2) 简化了聚合类
2. 主要缺点:
1) 增加新的聚合类需要对应增加新的迭代器类,类的个数会成对增加,增加了系统的复杂性
2) 迭代器设计难度大,需要充分考虑系统将来的扩展
3. 使用场景
1) 访问一个聚合对象的内容而无须暴露它的内部实现表示
2) 需要为一个聚合对象提供多种遍历方式
3) 为遍历不同的聚合结构提供统一的接口