第19章 迭代器模式
19.1 迭代器模式概述
聚合对象(Aggregate Classes):存储多个成员对象(元素)的类。
拥有的职责:
- 存储数据
- 遍历数据
从依赖性来看,前者是聚合对象的基本职责,后者是可变化的,又是可分离的。将遍历数据的行为从聚合对象中分离出来,封装在迭代器对象中,由迭代器来遍历聚合对象内部数据的行为,简化设计。
迭代器对象(Iterator Pattern):提供一种方法顺序访问一个聚合对象中的各个元素,而又不用暴露该对象的内部表示。
- 对象行为型模式
- 游标模式(Cursor)
19.2 迭代器模式结构与实现
19.2.1 迭代器模式结构
- Iterator(抽象迭代器):它定义了访问和遍历元素的接口,声明了用于遍历数据元素的方法,例如用于获取第一个元素的 first() 方法、用于访问下一个元素的 next() 方法、用于判断是否还有下一个元素的 hasNext() 方法、用于获取当前元素的 currentItem() 方法等,在具体迭代器中将实现这些方法。
- Concretelterator(具体迭代器):它实现了抽象迭代器接口,完成对聚合对象的遍历,同时在具体迭代器中通过游标来记录在聚合对象中所处的当前位置,在具体实现时游标通常是一个表示位置的非负整数。
- Aggregate(抽象聚合类):它用于存储和管理元素对象,声明一个 crcateltcrator() 方法用于创建一个迭代器对象,充当抽象迭代器工厂角色。
- ConcreteAggregate(具体聚合类):它是抽象聚合类的子类,实现了在抽象聚合类中声明的 createlterator() 方法,该方法返回一个与该具体聚合类对应的具体迭代器 Concretelterator 实例。
19.2.2 迭代器模式实现
在迭代器模式中提供了一个外部的迭代器来对聚合对象进行访问和遍历,迭代器定义了一个访问该聚合元素的接口,并且可以跟踪当前遍历的元素,了解哪些元素已经遍历过,哪些没有。迭代器的引入将使对一个复杂聚合对象的操作变得简单。
迭代器模式中应用了工厂方法模式
- 抽象迭代器-抽象产品角色
- 具体迭代器-具体产品角色
- 抽象聚合类-抽象工厂角色
- 具体聚合类-具体工厂角色
19.2.2
19.3 迭代器模式应用实例
实例说明
某软件公司为某商场开发了一套销售管理系,在对该系统进行分析和设计时,开发人员发现经常需要对系统中的商品数据、客户数据等进行遍历,为了复用这些遍历代码,开发人员设计了一个抽象的数据集合类AbstractObjectList,而将存储商品和客户等数据的类作为其子类,AbstractObjectList类的结构如图所示:
List 类型的对象object用于存储数据,方法说明:
AbstractObjectList类的子类ProductList和CustomerList分别用于存储商品数据和客户数据。
通过分析发现AbstractObjectList类的职责非常重,它既负责存储和管理数据,又负责遍历数据,违反了单一职责原则,实现代码将非常复杂。因此开发人员决定使用迭代器模式对AbstractObjectList类进行重构,将负责遍历数据的方法提取出来封装到专门的类中,实现数据存储和数据遍历分离,还可以给不同的具体数据集合类提供不同的遍历方式。
现给出使用迭代器模式重构后的解决方案。
实例类图
- 抽象聚合类
- AbstractObjectList
- 具体聚合类
- ProductList
- 抽象迭代器
- AbstractIterator
- 具体迭代器
- ProfuctIterator
自定义迭代器的实现过程(没有使用 JDK 内置迭代器:实现对一个 List 对象的正向遍历)
实例代码
AbstractObjectList:抽象聚合类。
package designpatterns.iterator;
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 addObject(Object obj) {
this.objects.add(obj);
}
public void removeObject(Object obj) {
this.objects.remove(obj);
}
public List<Object> getObjects() {
return this.objects;
}
//声明创建迭代器对象的抽象工厂方法
public abstract AbstractIterator createIterator();
}
ProductList:商品数据类,充当具体聚合类。
package designpatterns.iterator;
import java.util.List;
public class ProductList extends AbstractObjectList {
public ProductList(List<Object> objects) {
super(objects);
}
//实现创建迭代器对象的具体工厂方法
@Override
public AbstractIterator createIterator() {
return new ProductIterator(this);
}
}
AbstractIterator:抽象迭代器。
package designpatterns.iterator;
public interface AbstractIterator {
public void next();//移至下一个元素
public boolean isLast();//判断是否为最后一个元素
public void previous();//移至上一个元素
public boolean isFirst();//判断是否为第一个元素
public Object getNextItem();//获取下一个元素
public Object getPreviousItem();//获取上一个元素
}
Productlterator:商品迭代器,充当具体迭代器。
package designpatterns.iterator;
import java.util.List;
public class ProductIterator implements AbstractIterator {
private List<Object> products;
private int cursor1;//定义一个游标,用于记录正向遍历的位置
private int cursor2;//定义一个游标,用于记录逆向遍历的位置
public ProductIterator(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() {
return (cursor2 == -1);
}
@Override
public Object getNextItem() {
return products.get(cursor1);
}
@Override
public Object getPreviousItem() {
return products.get(cursor2);
}
}
Client:客户端测试类。
package designpatterns.iterator;
import java.util.ArrayList;
import java.util.List;
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;
AbstractIterator iterator;
list = new ProductList(products);//创建聚合对象
iterator = list.createIterator();//创建迭代器对象
System.out.println("正向遍历:");
while (!iterator.isLast()) {
System.out.print(iterator.getNextItem() + ",");
iterator.next();
iterator.next();
}
System.out.println();
System.out.println("—---------------");
System.out.println("逆向遍历:");
while (!iterator.isFirst()) {
System.out.print(iterator.getPreviousItem() + ",");
iterator.previous();
}
}
}
结果及分析
- 需要增加一个新的具体聚合类:增加一个新的聚合子类和一个新的具体迭代器类;
- 切换一个迭代器:增加一个新的具体迭代器类;
- 增加新的方法:需要修改抽象迭代器源代码,违反了开闭原则。
19.4 使用内部类实现迭代器
上述采用关联关系使得具体迭代器类访问具体聚合类,也可以采用将迭代器类设计为聚合类的内部类。
将 Productlterator 类作为 ProductList 类的内部类
package designpatterns.iterator;
import java.util.List;
public class ProductList extends AbstractObjectList {
public ProductList(List<Object> objects) {
super(objects);
}
//实现创建迭代器对象的具体工厂方法
@Override
public AbstractIterator createIterator() {
return new ProductIterator(this);
}
//商品迭代器:具体迭代器,内部类实现
private class ProductIterator implements AbstractIterator {
private int cursor1;//定义一个游标,用于记录正向遍历的位置
private int cursor2;//定义一个游标,用于记录逆向遍历的位置
public ProductIterator(ProductList list) {
cursor1 = 0;//设置正向遍历游标的初始值
cursor2 = objects.size() - 1;//设置逆向遍历游标的初始值
}
@Override
public void next() {
if (cursor1 < objects.size()) {
cursor1++;
}
}
@Override
public boolean isLast() {
return (cursor1 == objects.size());
}
@Override
public void previous() {
if (cursor2 > -1) {
cursor2--;
}
}
@Override
public boolean isFirst() {
return (cursor2 == -1);
}
@Override
public Object getNextItem() {
return objects.get(cursor1);
}
@Override
public Object getPreviousItem() {
return objects.get(cursor2);
}
}
}
19.5 Java 内置迭代器
为了让开发人员能够更加方便地操作聚合对象,在Java,C#等编程语言中提供了内置迭代器。
public interface Collection<E> extends Iterable<E> {
...
/**
* Returns an iterator over the elements in this collection. There are no
* guarantees concerning the order in which the elements are returned
* (unless this collection is an instance of some class that provides a
* guarantee).
*
* @return an <tt>Iterator</tt> over the elements in this collection
*/
Iterator<E> iterator();
...
}
iterator() : 返回一个 Iterator 类型的迭代器,以便遍历聚合中的元素。
具体实现的接口
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
hasNext()
用于判断聚合对象中是否还存在下一个元素,为了不抛出异常,在每次调用next()
之前需要先调用hasNext(),如果有可供访问的元素,则返回 true;next()
方法用于将游标移至下一个元素,通过它可以逐个访问聚合中的元素,它返回游标所越过的那个元素的引用;remove()
方法用于删除上次调用next()
时所返回的元素。
删除聚合对象的第一个元素:
Iterator iterator = collection.iterator();//collection是已实例化的聚合对象
iterator.next();//跳过第一个元素
iterator.remove();//删除第一个元素
删除两个相邻的元素:
iterator.remove();
iterator.next();//如果删除此行代码程序将抛异常
iterator.remove();
package designpatterns.iterator;
import java.util.ArrayList;
import java.util.List;
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;
AbstractIterator iterator;
list = new ProductList(products);//创建聚合对象
iterator = list.createIterator();//创建迭代器对象
System.out.println("正向遍历:");
while (!iterator.isLast()) {
System.out.print(iterator.getNextItem() + ",");
iterator.next();
iterator.next();
}
System.out.println();
System.out.println("—---------------");
System.out.println("逆向遍历:");
while (!iterator.isFirst()) {
System.out.print(iterator.getPreviousItem() + ",");
iterator.previous();
}
}
}
package designpatterns.iterator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
public class IteratorDemo {
public static void process(Collection c) {
Iterator i = c.iterator();//创建迭代器对象
//通过迭代器遍历聚合对象
while (i.hasNext()) {
System.out.println(i.next().toString());
}
}
public static void main(String[] args) {
Collection persons;
persons = new HashSet(); //创建一个ArrayList类型的聚合对象
// persons.add("张无忌");
persons.add("小龙女");
persons.add("令狐冲");
persons.add("韦小宝");
persons.add("袁紫衣");
persons.add("小龙女");
process(persons);
}
}