迭代器模式
提供一种方法顺序的访问一个聚合对象(数组,堆栈,列表,散列表等)中的各个元素,而不暴露其内部的表示。
类型:
行为型模式(类与类之间的行为型模式)
迭代器模式的几个角色:
- 抽象容器类:定义具体容器中的方法
- 具体容器类:用来存放聚合对象中的元素
- 抽象迭代器:提供一种方式,使得实现了此接口的聚合对象通过迭代的方式遍历元素
- 具体聚合对象:数组,堆栈,列表等
迭代器的关系图:
迭代器模式示例:
抽象容器类:
/**
* Create by zhaihongwei on 2018/3/27
* 抽象容器类
*/
public interface MyContainer<E> {
void add(E e);
void remove(E e);
MyIterator getMyIterator(MyIterator myIterator);
}
具体容器类:
/**
* Create by zhaihongwei on 2018/3/27
* 具体容器类,用来存放聚合对象中遍历的每一个元素
*/
public class ConcreteContainer<E> implements MyContainer {
public List<E> list = new ArrayList<>();
/**
* 在容器中添加指定元素
* @param e
*/
@Override
public void add(Object e) {
list.add((E) e);
}
/**
* 删除容器中的指定元素
*/
@Override
public void remove(Object e) {
list.remove(e);
}
/**
* 获取具体的迭代器对象
* @return
*/
@Override
public MyIterator getMyIterator(MyIterator myIterator) {
return myIterator;
}
}
抽象迭代器类:
/**
* Create by zhaihongwei on 2018/3/27
* 抽象迭代器类
*/
public interface MyIterator<E> {
boolean hasNext();
E next();
}
聚合对象:
/**
* Create by zhaihongwei on 2018/3/27
* 聚合对象类,需要实现抽象迭代器类
*/
public class AggregateObject<E> implements MyIterator {
public List<E> list = new ArrayList<>();
private int index;// 索引
/**
* 判断聚合对象中是否还有下一个元素
* @return
*/
@Override
public boolean hasNext() {
if(list.size() == index) {
// 没有下一个元素了
return false;
}
return true;
}
/**
* 返回聚合对象中的下一个元素
* @return
*/
@Override
public E next() {
E e = null;
if(this.hasNext()) {
e = list.get(index++);
}
return e;
}
}
测试类:
/**
* Create by zhaihongwei on 2018/3/27
*/
public class IteratorTest {
public static void main(String[] args) {
// 创建聚合对象,并存入具体元素
AggregateObject<Object> iterator = new AggregateObject<>();
List<Object> list = iterator.list;
list.add("一号");
list.add("二号");
list.add("三号");
// 将聚合对象中的所有元素装入容器中
ConcreteContainer<Object> container = new ConcreteContainer<>();
MyIterator myIterator = container.getMyIterator(iterator);
while (myIterator.hasNext()) {
container.add(myIterator.next());
}
// 遍历容器中的所有元素
for (Object cont : container.list) {
System.out.println(cont);
}
}
}
总结:
上面的例子,只是简单的介绍了迭代器模式的实现过程,可能大家看到这里却不明白迭代器模式到底有什么用,下面将用HeadFirst中的例子,并进行了一些改变,来讲述迭代器的作用(因为本人想不出来比这个例子好的—-QAQ)。
例子:
从前有两家餐馆,一家是早餐店,一家是午餐店,每家餐馆都有各自的菜单,现在一个大款收购了这两家餐馆,所以两家各自的菜单需要合并,但是早餐店的菜单是通过ArrayList来实现的,而午餐店的菜单是通过数组来实现的,并且每家都不愿意向对方妥协修改自己的源代码,所以没有办法直接合,先看以下的代码:
注意:
因为java已经为我们提供了Iterator类了,所以下面的例子使用java中提供的Iterator类来实现。
早餐店菜单:
/**
* Create by zhaihongwei on 2018/3/28
*/
public class BreakfastMenu {
private List menu = new ArrayList<>();
/**
* 早餐店的菜单中已经有的
*/
public void setMenu() {
menu.add("皮蛋瘦肉粥");
menu.add("肉蟹龙虾粥");
menu.add("白粥");
menu.add("豆浆");
}
public List getMenu() {
return menu;
}
}
午餐店菜单
/**
* Create by zhaihongwei on 2018/3/28
*/
public class LunchMenu {
private String[] menu = new String[5];
/**
* 午餐店已经有的菜单
*/
public void setMenu() {
menu[0] = "西红柿炒蛋";
menu[1] = "水蒸蛋";
menu[2] = "油泼面";
menu[4] = "白米饭";
}
public String[] getMenu() {
return menu;
}
}
新的菜单
/**
* Create by zhaihongwei on 2018/3/28
* 新的菜单类,相当于容器
*/
public class NewMenu {
private List newMenu = new ArrayList();
public List getNewMenu() {
return newMenu;
}
/**
* 给新的餐单添加菜品
* 注意:不考虑数组和集合之间的操作方法,为了说明迭代器的作用
* @param breakfastMenu
* @param lunchMenu
*/
public void setNewMenu(List breakfastMenu,String[] lunchMenu) {
for (Object item : breakfastMenu) {
newMenu.add(item);
}
for (Object item : lunchMenu) {
newMenu.add(item);
}
}
}
注意:
因为早餐店的菜单是List,而午餐店的菜单是数组,所以我们必须分别遍历,所以下面使用迭代器进行改造。
因为早餐店是List,list已经实现了Iterator接口了,我们可以直接使用iterator()方法,而数组没有办法直接使用iterator()方法。需要我们自己去实现。
迭代器改造午餐店菜单:
/**
* Create by zhaihongwei on 2018/3/28
*/
public class LunchMenu implements Iterator{
private String[] menu = new String[5];
private int index;
/**
* 午餐店已经有的菜单
*/
public void setMenu() {
menu[0] = "西红柿炒蛋";
menu[1] = "水蒸蛋";
menu[2] = "油泼面";
menu[3] = "白米饭";
}
public String[] getMenu() {
return menu;
}
@Override
public boolean hasNext() {
if (index >= menu.length-1 || menu[index] == null) {
// 没有下一个元素了
return false;
}
return true;
}
@Override
public Object next() {
Object o = null;
if(hasNext()) {
o = menu[index];
index++;
}
return o;
}
}
新的菜单类:
/**
* Create by zhaihongwei on 2018/3/28
* 新的菜单类,相当于容器
*/
public class NewMenu2 {
private List newMenu = new ArrayList();
private BreakfastMenu breakfastMenu;
private LunchMenu lunchMenu;
public NewMenu2(BreakfastMenu breakfastMenu,LunchMenu lunchMenu) {
this.breakfastMenu = breakfastMenu;
this.lunchMenu = lunchMenu;
}
public List getNewMenu() {
return newMenu;
}
public void setNewMenu(){
Iterator breakfastMenuIterator = breakfastMenu.getMenu().iterator();
setNewMenu(breakfastMenuIterator);
setNewMenu(lunchMenu);
}
private void setNewMenu(Iterator iterator) {
while (iterator.hasNext()) {
newMenu.add(iterator.next());
}
}
}
测试类:
/**
* Create by zhaihongwei on 2018/3/27
*/
public class IteratorTest {
public static void main(String[] args) {
BreakfastMenu breakfastMenu = new BreakfastMenu();
breakfastMenu.setMenu();
LunchMenu lunchMenu = new LunchMenu();
lunchMenu.setMenu();
NewMenu2 newMenu2 = new NewMenu2(breakfastMenu, lunchMenu);
newMenu2.setNewMenu();
List newMenu = newMenu2.getNewMenu();
for (Object item : newMenu) {
System.out.println(item);
}
}
}
总结:
通过上面的例子你应该能够感受到迭代器模式的作用了,想一想如果这个大款继续收购晚餐店,夜宵店的话,没有迭代器的情况下就会出现很多类似的遍历操作,而迭代器的优势就更加明显。
迭代器模式的优缺点:
优点:
- 简化了遍历的方式,不需要考虑聚合对象本身的内部算法
- 提供多种的遍历方式
缺点:
- 自己实现迭代器会比较繁琐,但是java中对于Collection类都已经为我们实现好了迭代器了,不需手动实现了。