迭代器模式的定义是:
提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部表示
问题:
这里引用《Head First》中的一个示例,如果一个聚合对象(菜单)中存在两种不同的存储结构(ArrayList & Array),该如何操作?
如果是简单的逐个遍历,程序的扩展性就会很差, 如果再增加新的存储结构,就需要对代码进行大量的修改
解决办法:
可以创建一个对象,将他称之为迭代器(Iterator),利用它来封装“遍历集合内每个对象的过程”,然后迭代器暗中根据容器的不同,使用不同的调用方法。
(这里可以这么理解,用迭代器去迭代,可以都调用next 和hasNext方法,然后在这两个方法中写具体的实现,这样我们如果要是需要新增存储结构的话,也只需要调用这两个方法,然后在对应的迭代器中去书写相应的迭代代码就可以了)
这里先介绍一下Java中的迭代器,Java中的迭代器位于java.util.Iterator包下,是一个轻量级的对象,创建代价小,主要方法有
1 hashNext (判断当前元素是否存在(不会移动指针)
2 next(返回当前元素,并指向下一个元素)
使用迭代器的好处:
1 提供了一种简单的遍历方式
2 支持以不同的方式去遍历一个聚合对象(ArrayList和Array的遍历方式不同,但是使用迭代器可以遍历这两种存储结构组成的聚合对象)
3 不会暴露内部实现细节
4 解耦合
5 具有扩展性,增加新的聚合类和迭代器都很方便,无需修改原有代码
例子代码实现:
Menu,提供通用的方法规范:
package spring.design.pattern.iterator;
import java.util.Iterator;
/**
* Description:
*
* @author 慕容蓝
* @version 1.0
* @date 2018/11/27 17:09
*/
public interface Menu {
Iterator createIterator();
}
菜单(数组),在这个类里,它会把数据存储的数据,交给迭代器进行处理
package spring.design.pattern.iterator;
import java.util.Iterator;
/**
* Description:晚餐类.
*
* @author 慕容蓝
* @version 1.0
* @date 2018/11/27 15:05
*/
public class DinerMenu implements Menu{
static final int Max_ITEMS = 6;
int numberOfItems = 0;
MenuItem[] menuItems;
public DinerMenu() {
menuItems = new MenuItem[Max_ITEMS];
AddItem("红烧肉", "Braised pork", false, 10.5);
AddItem("番茄炒蛋", "Tomato scrambled eggs", false, 8.5);
}
public void AddItem(String name, String description, Boolean vegetarian, double price) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
if (numberOfItems > Max_ITEMS) {
throw new RuntimeException("菜单已满");
} else {
menuItems[numberOfItems] = menuItem;
numberOfItems++;
}
}
@Override
public Iterator createIterator(){
return new DinerMenuIterator(menuItems);
}
}
菜单(集合),同上
package spring.design.pattern.iterator;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Iterator;
/**
* Description:早餐类.
*
* @author 慕容蓝
* @version 1.0
* @date 2018/11/27 14:59
*/
public class PancakeHouseMenu implements Menu{
ArrayList<MenuItem> menuItems;
public PancakeHouseMenu() {
menuItems = new ArrayList();
AddItem("牛奶", "milk", false, 3.0);
AddItem("面包", "bread", false, 1.0);
}
public void AddItem(String name, String description, Boolean vegetarian, double price) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
menuItems.add(menuItem);
}
@Override
public Iterator createIterator() {
return menuItems.iterator();
}
}
数组&集合中存储的对象:
package spring.design.pattern.iterator;
/**
* Description:菜单类.
*
* @author 慕容蓝
* @version 1.0
* @date 2018/11/27 14:55
*/
public class MenuItem {
private String name;
private String description;
private boolean vegetarin;
private double price;
public MenuItem(String name, String description, boolean vegetarin, double price) {
this.name = name;
this.description = description;
this.vegetarin = vegetarin;
this.price = price;
}
public double getPrice() {
return price;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public boolean isVegetarin() {
return vegetarin;
}
}
数组的迭代器,这里重写了迭代器的三个方法hasNext next remove:
package spring.design.pattern.iterator;
import java.util.Iterator;
/**
* Description:晚餐菜单迭代器.
*
* @author 慕容蓝
* @version 1.0
* @date 2018/11/27 15:23
*/
public class DinerMenuIterator implements Iterator {
/** position记录当前数组遍历的位置 */
int position = 0;
MenuItem[] items;
public DinerMenuIterator(MenuItem[] items) {
this.items = items;
}
@Override
public boolean hasNext() {
if (position >= items.length || items[position] == null) {
return false;
}
return true;
}
@Override
public Object next() {
MenuItem menuItem = items[position];
position = position + 1;
return menuItem;
}
@Override
public void remove() {
if (position <= 0) {
throw new IllegalStateException("You can't remove an item you've done at least one next()");
}
if (items[position - 1] != null) {
for (int i = position - 1; i < (items.length - 1); i++) {
items[i] = items[i + 1];
}
items[items.length - 1] = null;
}
}
}
服务员类,负责打印数据:
package spring.design.pattern.iterator;
import java.util.Iterator;
/**
* Description:服务员类.
*
* @author muronglan
* @version 1.0
* @date 2018/11/27 15:30
*/
public class Waitress {
/** init() */
Menu pancakeHouseMenu ;
Menu dinerMenu ;
public Waitress(Menu pancakeHouseMenu, Menu dinerMenu) {
this.pancakeHouseMenu = pancakeHouseMenu;
this.dinerMenu = dinerMenu;
}
public void printMenu() {
Iterator pancakeIterator = pancakeHouseMenu.createIterator();
Iterator dinerIterator = dinerMenu.createIterator();
System.out.println("MENU\n --- \nBREAKFAST");
printMenu(pancakeIterator);
System.out.println("\nLUNCH");
printMenu(dinerIterator);
}
public void printMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem) iterator.next();
System.out.println(menuItem.getName() + ",");
System.out.println(menuItem.getPrice() + " --- ");
System.out.println(menuItem.getDescription());
}
}
}
测试类,负责展现效果:
package spring.design.pattern.iterator;
/**
* Description:测试类.
*
* @author 慕容蓝
* @version 1.0
* @date 2018/11/27 16:04
*/
public class Test {
public static void main(String[] args) {
PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
DinerMenu dinerMenu = new DinerMenu();
Waitress waitress = new Waitress(pancakeHouseMenu,dinerMenu);
waitress.printMenu();
}
}
找时间补上一张UML图
在Java代码中的集合中,也是使用到了迭代器
Collection接口,继承了Iteratable接口,该接口中的Iterator方法可以产生一个
Iterator对象:
public interface Collection<E> extends Iterable<E> {…}
/**
* Performs the given action for each element of the {@code Iterable}
* until all elements have been processed or the action throws an
* exception. Unless otherwise specified by the implementing class,
* actions are performed in the order of iteration (if an iteration order
* is specified). Exceptions thrown by the action are relayed to the
* caller.
*
* @implSpec
* <p>The default implementation behaves as if:
* <pre>{@code
* for (T t : this)
* action.accept(t);
* }</pre>
*
* @param action The action to be performed for each element
* @throws NullPointerException if the specified action is null
* @since 1.8
*/
大概意思是对{@code Iterable} 的每个元素执行给定操作,如果产生了异常,异常会被抛给调用者
然后使用Iterator就可以对Conllection中的元素进行迭代操作:
public interface Iterator<E> {
/**
* 判断当前元素是否存在(不会移动指针)
*/
boolean hasNext();
/**
* 返回当前元素,并指向下一个元素
*/
E next();
…
}
我们可以通过增强型for循环去完成集合中的迭代,也可以自己去调用iterator方法,创建一个迭代器
package spring;
import java.util.ArrayList;
import java.util.List;
/**
* Description:
*
* @author 慕容蓝
* @version 1.0
* @date 2018/11/27 11:52
*/
public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
for (Integer i : list) {
System.out.print(i);
}
}
}
package spring;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Description:
*
* @author 慕容蓝
* @version 1.0
* @date 2018/11/27 11:52
*/
public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}