迭代器模式 (Iterator Pattern)
概述
迭代器模式是一种行为型设计模式,它提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。
意图
- 提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示
适用场景
- 访问一个聚合对象的内容而无须暴露它的内部表示
- 需要为聚合对象提供多种遍历方式
- 为遍历不同的聚合结构提供统一的接口
结构
┌─────────────┐ ┌─────────────┐
│ Client │──────────>│ Iterator │
├─────────────┤ ├─────────────┤
│ │ │ + first() │
└─────────────┘ │ + next() │
│ + isDone() │
│ + currentItem() │
└─────────────┘
▲
│
┌─────────────┐ ┌─────────────┐
│ Aggregate │<─────────│ConcreteIterator│
├─────────────┤ ├─────────────┤
│ + createIterator()│ │ - aggregate │
└─────────────┘ │ + first() │
│ + next() │
│ + isDone() │
│ + currentItem() │
└─────────────┘
▲
│
┌─────────────┐
│ConcreteAggregate│
├─────────────┤
│ + createIterator()│
└─────────────┘
参与者
- Iterator:迭代器定义访问和遍历元素的接口
- ConcreteIterator:具体迭代器实现迭代器接口,并跟踪聚合对象中的当前位置
- Aggregate:聚合定义创建相应迭代器对象的接口
- ConcreteAggregate:具体聚合实现创建相应迭代器的接口,该操作返回ConcreteIterator的一个适当的实例
示例代码
下面是一个完整的迭代器模式示例,以自定义集合为例:
java
import java.util.ArrayList;
import java.util.List;
// Iterator - 迭代器接口
public interface Iterator<T> {
boolean hasNext();
T next();
void reset();
}
// Aggregate - 聚合接口
public interface Aggregate<T> {
Iterator<T> createIterator();
}
// ConcreteAggregate - 具体聚合类
public class ConcreteAggregate<T> implements Aggregate<T> {
private List<T> items = new ArrayList<>();
public void add(T item) {
items.add(item);
}
public T get(int index) {
return items.get(index);
}
public int size() {
return items.size();
}
@Override
public Iterator<T> createIterator() {
return new ConcreteIterator(this);
}
}
// ConcreteIterator - 具体迭代器
public class ConcreteIterator<T> implements Iterator<T> {
private ConcreteAggregate<T> aggregate;
private int current = 0;
public ConcreteIterator(ConcreteAggregate<T> aggregate) {
this.aggregate = aggregate;
}
@Override
public boolean hasNext() {
return current < aggregate.size();
}
@Override
public T next() {
if (hasNext()) {
return aggregate.get(current++);
}
return null;
}
@Override
public void reset() {
current = 0;
}
}
// Client - 客户端
public class Client {
public static void main(String[] args) {
// 创建聚合对象
ConcreteAggregate<String> aggregate = new ConcreteAggregate<>();
aggregate.add("元素1");
aggregate.add("元素2");
aggregate.add("元素3");
aggregate.add("元素4");
aggregate.add("元素5");
// 创建迭代器
Iterator<String> iterator = aggregate.createIterator();
// 使用迭代器遍历聚合对象
System.out.println("第一次遍历:");
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println(item);
}
// 重置迭代器
iterator.reset();
System.out.println("\n重置后第二次遍历:");
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println(item);
}
}
}
另一个示例 - 反向迭代器
java
// ReverseIterator - 反向迭代器
public class ReverseIterator<T> implements Iterator<T> {
private ConcreteAggregate<T> aggregate;
private int current;
public ReverseIterator(ConcreteAggregate<T> aggregate) {
this.aggregate = aggregate;
this.current = aggregate.size() - 1;
}
@Override
public boolean hasNext() {
return current >= 0;
}
@Override
public T next() {
if (hasNext()) {
return aggregate.get(current--);
}
return null;
}
@Override
public void reset() {
current = aggregate.size() - 1;
}
}
// Client - 客户端
public class Client {
public static void main(String[] args) {
// 创建聚合对象
ConcreteAggregate<String> aggregate = new ConcreteAggregate<>();
aggregate.add("元素1");
aggregate.add("元素2");
aggregate.add("元素3");
aggregate.add("元素4");
aggregate.add("元素5");
// 创建正向迭代器
Iterator<String> forwardIterator = aggregate.createIterator();
System.out.println("正向遍历:");
while (forwardIterator.hasNext()) {
String item = forwardIterator.next();
System.out.println(item);
}
// 创建反向迭代器
Iterator<String> reverseIterator = new ReverseIterator<>(aggregate);
System.out.println("\n反向遍历:");
while (reverseIterator.hasNext()) {
String item = reverseIterator.next();
System.out.println(item);
}
}
}
Java中的迭代器模式
Java中的集合框架广泛使用了迭代器模式:
java
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class JavaIteratorExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
list.add("JavaScript");
// 使用迭代器遍历
System.out.println("使用迭代器遍历:");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String language = iterator.next();
System.out.println(language);
}
// 使用增强for循环遍历(底层也是迭代器)
System.out.println("\n使用增强for循环遍历:");
for (String language : list) {
System.out.println(language);
}
// 使用Java 8的forEach方法
System.out.println("\n使用forEach方法遍历:");
list.forEach(System.out::println);
}
}
自定义迭代器实现
下面是一个更复杂的自定义迭代器实现,以菜单系统为例:
java
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
// MenuItem - 菜单项
public class MenuItem {
private String name;
private String description;
private boolean vegetarian;
private double price;
public MenuItem(String name, String description, boolean vegetarian, double price) {
this.name = name;
this.description = description;
this.vegetarian = vegetarian;
this.price = price;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public boolean isVegetarian() {
return vegetarian;
}
public double getPrice() {
return price;
}
}
// MenuComponent - 菜单组件抽象类
public abstract class MenuComponent {
public void add(MenuComponent menuComponent) {
throw new UnsupportedOperationException();
}
public void remove(MenuComponent menuComponent) {
throw new UnsupportedOperationException();
}
public MenuComponent getChild(int i) {
throw new UnsupportedOperationException();
}
public String getName() {
throw new UnsupportedOperationException();
}
public String getDescription() {
throw new UnsupportedOperationException();
}
public boolean isVegetarian() {
throw new UnsupportedOperationException();
}
public double getPrice() {
throw new UnsupportedOperationException();
}
public abstract Iterator<MenuComponent> createIterator();
public abstract void print();
}
// MenuItem - 菜单项实现
public class MenuItem extends MenuComponent {
private String name;
private String description;
private boolean vegetarian;
private double price;
public MenuItem(String name, String description, boolean vegetarian, double price) {
this.name = name;
this.description = description;
this.vegetarian = vegetarian;
this.price = price;
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return description;
}
@Override
public boolean isVegetarian() {
return vegetarian;
}
@Override
public double getPrice() {
return price;
}
@Override
public Iterator<MenuComponent> createIterator() {
return new NullIterator();
}
@Override
public void print() {
System.out.print(" " + getName());
if (isVegetarian()) {
System.out.print("(v)");
}
System.out.println(", " + getPrice());
System.out.println(" -- " + getDescription());
}
}
// Menu - 菜单实现
public class Menu extends MenuComponent {
private List<MenuComponent> menuComponents = new ArrayList<>();
private String name;
private String description;
public Menu(String name, String description) {
this.name = name;
this.description = description;
}
@Override
public void add(MenuComponent menuComponent) {
menuComponents.add(menuComponent);
}
@Override
public void remove(MenuComponent menuComponent) {
menuComponents.remove(menuComponent);
}
@Override
public MenuComponent getChild(int i) {
return menuComponents.get(i);
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return description;
}
@Override
public Iterator<MenuComponent> createIterator() {
return new CompositeIterator(menuComponents.iterator());
}
@Override
public void print() {
System.out.print("\n" + getName());
System.out.println(", " + getDescription());
System.out.println("---------------------");
Iterator<MenuComponent> iterator = menuComponents.iterator();
while (iterator.hasNext()) {
MenuComponent menuComponent = iterator.next();
menuComponent.print();
}
}
}
// NullIterator - 空迭代器
public class NullIterator implements Iterator<MenuComponent> {
@Override
public boolean hasNext() {
return false;
}
@Override
public MenuComponent next() {
return null;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
// CompositeIterator - 组合迭代器
public class CompositeIterator implements Iterator<MenuComponent> {
private Stack<Iterator<MenuComponent>> stack = new Stack<>();
public CompositeIterator(Iterator<MenuComponent> iterator) {
stack.push(iterator);
}
@Override
public boolean hasNext() {
if (stack.empty()) {
return false;
} else {
Iterator<MenuComponent> iterator = stack.peek();
if (!iterator.hasNext()) {
stack.pop();
return hasNext();
} else {
return true;
}
}
}
@Override
public MenuComponent next() {
if (hasNext()) {
Iterator<MenuComponent> iterator = stack.peek();
MenuComponent component = iterator.next();
if (component instanceof Menu) {
stack.push(component.createIterator());
}
return component;
} else {
return null;
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
// Waitress - 服务员
public class Waitress {
private MenuComponent allMenus;
public Waitress(MenuComponent allMenus) {
this.allMenus = allMenus;
}
public void printMenu() {
allMenus.print();
}
public void printVegetarianMenu() {
Iterator<MenuComponent> iterator = allMenus.createIterator();
System.out.println("\nVEGETARIAN MENU\n----");
while (iterator.hasNext()) {
MenuComponent menuComponent = iterator.next();
try {
if (menuComponent.isVegetarian()) {
menuComponent.print();
}
} catch (UnsupportedOperationException e) {
// 不处理
}
}
}
}
// Client - 客户端
public class Client {
public static void main(String[] args) {
// 创建所有菜单
MenuComponent allMenus = new Menu("所有菜单", "所有菜单组合");
// 创建早餐菜单
MenuComponent breakfastMenu = new Menu("早餐菜单", "早餐菜单");
breakfastMenu.add(new MenuItem("煎饼", "煎饼配豆浆", true, 3.99));
breakfastMenu.add(new MenuItem("包子", "肉包子", false, 2.99));
// 创建午餐菜单
MenuComponent lunchMenu = new Menu("午餐菜单", "午餐菜单");
lunchMenu.add(new MenuItem("汉堡", "牛肉汉堡", false, 8.99));
lunchMenu.add(new MenuItem("沙拉", "蔬菜沙拉", true, 5.99));
// 创建晚餐菜单
MenuComponent dinnerMenu = new Menu("晚餐菜单", "晚餐菜单");
dinnerMenu.add(new MenuItem("牛排", "烤牛排", false, 15.99));
dinnerMenu.add(new MenuItem("意大利面", "素食意大利面", true, 12.99));
// 创建甜点菜单
MenuComponent dessertMenu = new Menu("甜点菜单", "甜点菜单");
dessertMenu.add(new MenuItem("蛋糕", "巧克力蛋糕", true, 4.99));
dessertMenu.add(new MenuItem("冰淇淋", "香草冰淇淋", true, 3.99));
// 将甜点菜单添加到晚餐菜单中
dinnerMenu.add(dessertMenu);
// 将所有菜单添加到总菜单中
allMenus.add(breakfastMenu);
allMenus.add(lunchMenu);
allMenus.add(dinnerMenu);
// 创建服务员
Waitress waitress = new Waitress(allMenus);
// 打印所有菜单
waitress.printMenu();
// 打印素食菜单
waitress.printVegetarianMenu();
}
}
优缺点
优点
- 它支持以不同的方式遍历一个聚合
- 简化了聚合对象的接口
- 在同一个聚合上可以有多个遍历同时进行
缺点
- 由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性
相关模式
- 组合模式:迭代器模式经常与组合模式一起使用,以遍历组合结构中的所有元素
- 工厂方法模式:迭代器通常使用工厂方法模式来创建
- 备忘录模式:迭代器模式可以使用备忘录模式来保存遍历状态
实际应用
- Java集合框架中的Iterator接口
- Java中的Enumeration接口
- 数据库游标
- 文件系统遍历
- XML/HTML文档解析
注意事项
- 迭代器模式中的迭代器应该是轻量级的,不应该包含过多的状态
- 迭代器模式中的聚合对象不应该暴露其内部结构
- 迭代器模式中的迭代器应该是独立的,不依赖于聚合对象的具体实现
- 迭代器模式中的迭代器应该是可重用的,可以在不同的聚合对象上使用