设计模式的艺术 行为型模式之迭代器模式
前言
现在的电视机都配置了一个遥控器,用户可以通过遥控器去选择上一个或者下一个台,我们只需要知道如何使用这个遥控器,而无须关注电视是怎么把电视频道放入其中的,在软件实际的开发中,也有这么一种类,它储存着多个成员对象,这些类通常称为聚合类,对应的对象称为聚合对象。为了方便操作这些聚合对象,同时可以很灵活的为聚合对象增加不同的遍历的方法,也需要类似电视机遥控器一样的角色,可以访问对象的同时又不暴露它内部的结构
什么是迭代器模式 Iterator Pattern
提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor),迭代器模式是一种对象行为型模式
迭代器模式的优点
(1)、支持以不同的方式遍历一个聚合对象,在同一个聚合对象上可以定义多种遍历方式。在迭代器模式中只需要用一个迭代器来替换原有的迭代器即可改变遍历算法,也可以自定义迭代器的子类以支持新的遍历方式。
(2)、迭代器简化了聚合类。由于引入了迭代器,在原有的聚合对象中不需要再自行提供数据遍历等方法,这样可以简化聚合类的设计
(3)、在迭代器模式中,由于引入了抽象层,增加新的聚合类和迭代器都很方便,无须修改原有代码,满足了开闭原则的要求
迭代器模式的缺点
(1)、由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对的增加,这在一定程度上增加了系统的复杂性
(2)、抽象迭代器的设计难度较大,需要充分考虑到系统将来的扩展,例如JDK中内置迭代器Iterator就无法实现逆向遍历,如果需要实现逆向遍历,只能通过其子类ListIerator等来实现,而ListIterator迭代器无法用于操作Set类型的聚合对象。在自定义迭代器时,创建一个考虑全面的抽象迭代器并不是一件很容易的事情
迭代器模式的适用场景
(1)、访问一个聚合对象的内容而无须暴露它的内部表示。将聚合对象的访问与内部数据的存储相分离,使得访问聚合对象时无须了解其内部实现细节
(2)、需要为一个聚合对象提供多种遍历方式
(3)、为遍历不同的聚合结构提供一个统一的接口,在该接口的实现类中为不同的聚合机构提供不同的遍历方式,而客户端可以统一的操作该接口
迭代器模式的具体实现
抽象聚合类
package com.company;
import java.util.ArrayList;
import java.util.List;
public abstract class AbstractObjectList {
protected List<Object> objects=new ArrayList<Object>();
public AbstractObjectList(List<Object> objects) {
this.objects = objects;
}
public void removeObject(Object object){
this.objects.remove(object);
}
public List getObjects(){
return this.objects;
}
//声明创建迭代器对象的抽象方法
public abstract AbstractIterator createIterator();
}
具体聚合类
package com.company;
import java.util.List;
//商品数据类:集体聚合类
public class ProductList extends AbstractObjectList {
public ProductList(List<Object> objects) {
super(objects);
}
@Override
//实现创建迭代器对象的具体工厂类
public AbstractIterator createIterator() {
return new ProductIterator(this);
}
}
抽象迭代器类
package com.company;
public interface AbstractIterator {
public void next(); //移至下一个元素
public boolean isLast(); //判断是否为最后一个元素
public void previous(); //移至上一个元素
public boolean isFirst(); //判断是否为第一个元素
public Object getNextItem(); //获取下一个元素
public Object getPreviousItem(); //获取上一个元素
}
具体产品迭代器类
package com.company;
import java.util.List;
//商品迭代器:具体迭代器
public class ProductIterator implements AbstractIterator {
private ProductList productList;
private List products;
private int cursor1; //定义一个游标,用于记录正向遍历的位置
private int cursor2; //定义一个游标,用于记录逆向遍历的位置
public ProductIterator(ProductList productList) {
this.productList = productList;
this.products=productList.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() {
return (cursor2==-1);
}
@Override
public Object getNextItem() {
return products.get(cursor1);
}
@Override
public Object getPreviousItem() {
return products.get(cursor2);
}
}
客户端测试类
package com.company;
import java.util.ArrayList;
import java.util.List;
public class Client {
public static void main(String[] args) {
List products = new ArrayList();
products.add("倚天剑");
products.add("屠龙刀");
products.add("断肠草");
products.add("葵花宝典");
products.add("四十二章经");
AbstractObjectList list;
AbstractIterator iterator;
list = new ProductList(products); //创建聚合对象
iterator = list.createIterator(); //创建迭代器对象
System.out.println("正向遍历");
while (!iterator.isLast()) {
System.out.println(iterator.getNextItem() + ",");
iterator.next();
}
System.out.println();
System.out.println("---------------------");
System.out.println("逆向遍历");
while (!iterator.isFirst()) {
System.out.println(iterator.getPreviousItem() + ",");
iterator.previous();
}
}
}