Java设计模式(16)之迭代器模式

迭代器模式

提供一种方法顺序的访问一个聚合对象(数组,堆栈,列表,散列表等)中的各个元素,而不暴露其内部的表示。

类型:

行为型模式(类与类之间的行为型模式)

迭代器模式的几个角色:

  • 抽象容器类:定义具体容器中的方法
  • 具体容器类:用来存放聚合对象中的元素
  • 抽象迭代器:提供一种方式,使得实现了此接口的聚合对象通过迭代的方式遍历元素
  • 具体聚合对象:数组,堆栈,列表等

迭代器的关系图:

这里写图片描述

迭代器模式示例:

抽象容器类:

/**
 * 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);
        }
    }
}

总结:

通过上面的例子你应该能够感受到迭代器模式的作用了,想一想如果这个大款继续收购晚餐店,夜宵店的话,没有迭代器的情况下就会出现很多类似的遍历操作,而迭代器的优势就更加明显。

迭代器模式的优缺点:

优点:

  1. 简化了遍历的方式,不需要考虑聚合对象本身的内部算法
  2. 提供多种的遍历方式

缺点:

  • 自己实现迭代器会比较繁琐,但是java中对于Collection类都已经为我们实现好了迭代器了,不需手动实现了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值