简介
迭代器模式(Iterator Pattern)又叫作游标模式(Cursor Pattern),它提供一种按顺序访问集合/容器对象元素的方法,而又无须暴露集合内部表示。迭代器模式可以为不同的容器提供一致的遍历行为,而不用关心容器内元素的组成结构,属于行为型设计模式。
通用模板
-
创建抽象迭代器:抽象迭代器负责定义访问和遍历元素的接口。
// 抽象迭代器 public interface Iterator <E>{E next();boolean hasNext(); }
-
创建具体迭代器:提供具体的元素遍历行为。
// 具体迭代器 public class ConcreteIterator<E> implements Iterator<E> {private List<E> list;private int cursor = 0;public ConcreteIterator(List<E> list) {this.list = list;}@Overridepublic E next() {return this.list.get(cursor++);}@Overridepublic boolean hasNext() {return this.cursor < this.list.size();} }
-
创建抽象容器:负责定义提供具体迭代器的接口。
// 抽象容器 public interface IAggregate <E>{boolean add(E element);boolean remove(E element);Iterator<E> iterator(); }
-
创建具体容器:抽象容器的具体实现类。
import java.util.ArrayList; import java.util.List;// 具体容器 public class ConcreteAggregate<E> implements IAggregate<E> {private List<E> list = new ArrayList<>();@Overridepublic boolean add(E element) {return this.list.add(element);}@Overridepublic boolean remove(E element) {return this.list.remove(element);}@Overridepublic Iterator<E> iterator() {return new ConcreteIterator<>(this.list);} }
模板测试
-
测试代码
public class Client {public static void main(String[] args) {// 创建一个容器对象ConcreteAggregate<String> aggregate = new ConcreteAggregate<>();// 添加元素aggregate.add("A");aggregate.add("B");aggregate.add("C");// 获取容器对象迭代器Iterator<String> iterator = aggregate.iterator();while (iterator.hasNext()){String element = iterator.next();System.out.println(element);}} }
-
测试结果
A B C
应用场景
迭代器模式在生活中应用得比较广泛。比如,物流系统中的传送带,不管传送的是什么物品,都被打包成一个个箱子,并且有一个统一的二维码。这样我们不需要关心箱子里是什么,在分发时只需要一个个检查发送的目的地即可。再比如,我们平时乘坐交通工具,都是统一刷卡或者刷脸进站,而不需要关心是男性还是女性、是残疾人还是正常人等信息。
我们把多个对象聚在一起形成的总体称为集合(Aggregate),集合对象是能够包容一组对象的容器对象。不同的集合其内部元素的聚合结构可能不同,而迭代器模式屏蔽了内部元素的获取细节,为外部提供一致的元素访问行为,解耦了元素迭代与集合对象间的耦合,并且通过提供不同的迭代器,可以为同一个集合对象提供不同顺序的元素访问行为,扩展了集合对象元素迭代功能,符合开闭原则。
迭代器模式适用于以下应用场景。
(1)访问一个集合对象的内容而无须暴露它的内部表示。
(2)为遍历不同的集合结构提供一个统一的访问接口。
说明:在日常开发中,我们几乎不会自己写迭代器。除非需要定制一个自己实现的数据结构对应的迭代器,否则,开源框架提供的API完全够用。
优点
(1)多态迭代:为不同的聚合结构提供一致的遍历接口,即一个迭代接口可以访问不同的集合对象。 (2)简化集合对象接口:迭代器模式将集合对象本身应该提供的元素迭代接口抽取到迭代器中,使集合对象无须关心具体迭代行为。
(3)元素迭代功能多样化:每个集合对象都可以提供一个或多个不同的迭代器,使得同种元素的聚合结构可以有不同的迭代行为。
(4)解耦迭代与集合:迭代器模式封装了具体的迭代算法,迭代算法的变化不会影响到集合对象的架构。
缺点
对于比较简单的遍历(如数组或者有序列表),使用迭代器模式遍历较为烦琐。
“生搬硬套”实战
场景描述
假设我们有一个餐厅菜单,菜单上有两个部分:早餐菜单和晚餐菜单。为了展示菜单上的项目,我们需要遍历这些项目。但是,我们不想直接暴露菜单内部的数据结构给客户,所以我们决定使用迭代器模式来隐藏这些细节。
代码开发
-
创建抽象迭代器(这里指迭代菜品的迭代器)
// 定义一个抽象的迭代器接口,用于遍历集合 public interface Iterator {boolean hasNext(); // 是否还有下一个元素Object next(); // 获取下一个元素 }
-
创建具体迭代器(这里指菜单迭代器)
import java.util.Vector;// 定义具体的菜单迭代器 public class MenuIterator implements Iterator {Vector<String> items; // 假设菜单用Vector存储int position;public MenuIterator(Vector<String> items) {this.items = items;position = 0;}@Overridepublic boolean hasNext() {return position < items.size() && items.get(position) != null;}@Overridepublic Object next() {String item = items.get(position);position = position + 1;return item;} }
-
创建抽象容器(这里指菜单容器)
// 定义一个抽象的聚合类,它持有迭代器对象 public interface Menu {Iterator createIterator(); }
-
创建具体容器(这里指具体的早餐菜单和晚餐菜单容器)
import java.util.Vector;// 早餐菜单具体聚合类 public class BreakfastMenu implements Menu {Vector<String> items;public BreakfastMenu() {items = new Vector<String>();addItem("包子");addItem("豆浆");addItem("油条");}public void addItem(String item) {items.add(item);}@Overridepublic Iterator createIterator() {return new MenuIterator(items);} }
import java.util.Vector;// 晚餐菜单具体聚合类 public class DinnerMenu implements Menu {Vector<String> items;public DinnerMenu() {items = new Vector<String>();addItem("红烧肉");addItem("清蒸鱼");addItem("拍黄瓜");}public void addItem(String item) {items.add(item);}@Overridepublic Iterator createIterator() {return new MenuIterator(items);} }
至此,我们就通过“生搬硬套”迭代器模式的模板设计出一套迭代菜单的案例,接下来我们进行测试:
-
测试代码
public class Client {public static void main(String[] args) {Menu breakfastMenu = new BreakfastMenu();Menu dinnerMenu = new DinnerMenu();System.out.println("早餐菜单:");printMenu(breakfastMenu);System.out.println("\n晚餐菜单:");printMenu(dinnerMenu);}public static void printMenu(Menu menu) {Iterator iterator = menu.createIterator();while (iterator.hasNext()) {System.out.println(iterator.next());}} }
-
测试结果
早餐菜单: 包子 豆浆 油条晚餐菜单: 红烧肉 清蒸鱼 拍黄瓜
总结
迭代器模式的本质是把集合对象的迭代行为抽离到迭代器中,提供一致的访问接口。通俗来讲就是提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。