设计模式(十六)迭代器模式 Iterator
- 什么时候需要用到迭代器模式?
有许多中方法,可以把对象堆起来放进一个集合(可以是数组、堆栈、列表、哈希表,等等)。
每一种类型的集合,都有各自适用的时机。但是某个时间段,客户端可能希望去遍历这个集合。
怎么做?
让客户去得到这个集合的具体实现?显然这不是很现实。
而且针对不同的集合,我们需要用不同的方式去遍历它,这需要去深入了解各种数据结构,对客户端很不友好。
这时候,我们希望创建一种超集合(super collection),是客户端能够使用统一的方法去遍历集合,同时不需要关心具体的数据结构。
这就是迭代器模式。
- 迭代器模式:
迭代器模式提供一种方法,顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
从 Java 的角度来说,迭代器模式就是 Iterator 接口。
- 模拟场景:
有一个水果商店(FruitShop),内部采取数组的方式存储数据。
有一个肉食商店(MeatShop),内部采用链表的方式存储数据。
客户端希望去遍历这些数据,
- 没有迭代器的实现:
public final class FruitShop { private String[] products = new String[MAX_PRODUCT]; private int index = 0; private static final int MAX_PRODUCT = 10; public void addProduct(String product) { if (index < MAX_PRODUCT) { products[index++] = product; } else { throw new RuntimeException("FruitShop is full"); } } public String[] getProducts() { return Arrays.copyOf(products, index); } }
public final class MeatShop { private List<String> products = new LinkedList<>(); public void addProduct(String product) { products.add(product); } public List<String> getProducts() { return products; } }
@Test void testFruitShop() { FruitShop fruitShop = new FruitShop(); fruitShop.addProduct("Apple"); fruitShop.addProduct("Orange"); String[] products = fruitShop.getProducts(); for (String product : products) { System.out.println(product); } } @Test void testMeatShop() { MeatShop meatShop = new MeatShop(); meatShop.addProduct("Beef"); meatShop.addProduct("Pork"); List<String> products = meatShop.getProducts(); for (String product : products) { System.out.println(product); } }
上面的代码有如下的问题:
- 两个 Shop 暴露了内部的数据结构。
- 客户端采取不同的方法去遍历数据。
- 包含迭代器的实现
public final class FruitShopIterator implements Iterator<String> { private String[] products = new String[MAX_PRODUCT]; private int index = 0; private int iteratorIndex = 0; private static final int MAX_PRODUCT = 10; public void addProduct(String product) { if (index < MAX_PRODUCT) { products[index++] = product; } else { throw new RuntimeException("FruitShop is full"); } } @Override public boolean hasNext() { return iteratorIndex < index; } @Override public String next() { return products[iteratorIndex++]; } }
public final class MeatShopIterator implements Iterator<String> { private List<String> products = new LinkedList<>(); private int iteratorIndex = 0; public void addProduct(String product) { products.add(product); } @Override public boolean hasNext() { return iteratorIndex < products.size(); } @Override public String next() { return products.get(iteratorIndex++); } }
@Test void testFruitShopIterator() { FruitShopIterator fruitShop = new FruitShopIterator(); fruitShop.addProduct("Apple"); fruitShop.addProduct("Orange"); while (fruitShop.hasNext()) { System.out.println(fruitShop.next()); } } @Test void testMeatShopIterator() { MeatShopIterator meatShop = new MeatShopIterator(); meatShop.addProduct("Beef"); meatShop.addProduct("Pork"); while (meatShop.hasNext()) { System.out.println(meatShop.next()); } }
可以看出:
- Iterator 提供了 hasNext() 和 next() 方法负责集合数据的遍历。
- Shop 类避免了暴露具体的数据结构。
- 客户端采用统一的方式去遍历数据。