博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
迭代器模式
阅读量:6851 次
发布时间:2019-06-26

本文共 6456 字,大约阅读时间需要 21 分钟。

hot3.png

      迭代器模式将一个集合给封装起来,主要是为用户提供了一种遍历其内部元素的方式。迭代器模式有两个优点:①提供给用户一个遍历的方式,而没有暴露其内部实现细节;②把元素之间游走的责任交给迭代器,而不是聚合对象,实现了用户与聚合对象之间的解耦。

      迭代器模式主要是通过Iterator接口来管理一个聚合对象的,而用户使用的时候只需要拿到一个Iterator类型的对象即可完成对该聚合对象的遍历。这里的聚合对象一般是指ArrayList,LinkedList和底层实现为数组等拥有一组相同或相似特性的对象。通过迭代器模式对聚合对象的遍历主要是通过Iterator接口的next(),hasNext()方法进行的,这里next()方法将返回当前遍历点的元素值,而hasNext()方法则表征当前遍历点之后还有没有元素。Iterator接口中还有一个remove()方法,该方法将移除当前遍历点的元素。在一般情况下不需要使用该方法,一些特殊的情况可以调用该方法,如果当前聚合对象的遍历不支持该操作,那么可以在该方法中跑出UnSupportedOperationException。

      这里我们以如下例子来对迭代器模式进行说明。现有两个餐厅的两套菜单,一套菜单是使用数组实现的,而另外一套菜单是使用ArrayList实现的。现在由于两个餐厅的合并而需要将两套菜单进行整合,由于双方的厨师都已经习惯了各自的菜单组装方式,因而都希望各自继续维护各自的菜单样式。但是,对于服务员来说,其为顾客提供菜单的时候则必须根据两套菜单进行两种不同方式的处理,这必然会增加服务员的工作难度,而且,如果后期有新的餐厅合并进来,比如其使用的菜单种类为HashMap,那么服务员将又会维护这一套菜单,这也不利于扩展。根据服务员的需求,其需要的是一个菜单列表,如果其面向的是各个不同的菜单类,那么势必会增加其工作难度,并且各个不同的菜单类中所提供的方法也不一定是服务员所需要的,因而,根据服务员的需求,这里需要制定一个菜单的规范,以实现服务员能够按照同一种方式对其进行遍历。这里就可以使用到迭代器模式,服务员只需要面向迭代器接口进行遍历,而各个厨师所拥有的菜单只需要实现该迭代器即可,其依然可以按照各自的方式维护其菜单项。这样就实现了不同的菜单与服务员的解耦。以下是使用迭代器模式解决该问题的具体代码。

菜单接口(主要包含创建迭代器的方法):

public interface Menu
{ Iterator
createIterator();}

菜单项:

public class MenuItem {    private String name;    private String description;    private boolean vegetarian;    private double price;    public MenuItem(String name, String description, boolean vegetarian, double price) {        this.name = name;        this.description = description;        this.vegetarian = vegetarian;        this.price = price;    }    public String getName() {        return name;    }    public String getDescription() {        return description;    }    public boolean isVegetarian() {        return vegetarian;    }    public double getPrice() {        return price;    }}

菜单类(菜单项的组装方式):

public class DinerMenu implements Menu {    private static final int MAX_ITEMS = 6;    private int numberOfItems = 0;    private MenuItem[] menuItems;    public DinerMenu() {        menuItems = new MenuItem[MAX_ITEMS];        addItem("Vegetarian BLT", "(Fakin') Bacon with lettuce & tomato on whole wheat", true, 2.99);        addItem("BLT", "Bacon with lettuce & tomato on whole wheat", false, 2.99);        addItem("Soup of the day", "Soup of the day, with a side of potato salad", false, 3.29);        addItem("Hotdog", "A hot dog, with saurkraut, relish, onions, topped with cheese", false, 3.05);    }    public void addItem(String name, String description, boolean vegetarian, double price) {        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);        if (numberOfItems >= MAX_ITEMS) {            System.out.println("Sorry, menu is full, Can't add item to menu");        } else {            menuItems[numberOfItems] = menuItem;            numberOfItems++;        }    }    @Deprecated    public MenuItem[] getMenuItems() {        return menuItems;    }    public Iterator createIterator() {        return new DinerMenuIterator(menuItems);    }}
public class PancakeHouseMenu implements Menu {    private ArrayList menuItems;    public PancakeHouseMenu() {        menuItems = new ArrayList<>();        addItem("K&B's Pancake Breakfast", "Pancakes with scrambled eggs, and toast", true, 2.99);        addItem("Regular Pancake Breakfast", "Pancakes with fried eggs, sausage", false, 2.99);        addItem("Blueberry Pancakes", "Pancakes made with fresh blueberries", true, 3.49);        addItem("Waffles", "Waffles, with your choice of blueberries or strawberries", true, 3.49);    }    public void addItem(String name, String description, boolean vegetarian, double price) {        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);        menuItems.add(menuItem);    }    @Deprecated    public ArrayList getMenuItems() {        return menuItems;    }    public Iterator createIterator() {        return menuItems.iterator();    }}

迭代器接口:

public interface Iterator
{ boolean hasNext(); T next();}

迭代器类:

public class DinerMenuIterator implements Iterator {    private MenuItem[] items;    private int position = 0;    public DinerMenuIterator(MenuItem[] items) {        this.items = items;    }    @Override    public boolean hasNext() {        return position < items.length && items[position] != null;    }    @Override    public MenuItem next() {        return items[position++];    }    @Override    public void remove() {        if (position <= 0) {            throw new IllegalStateException("You can't remove an item until 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;        }    }}
public class PancakeHouseIterator implements Iterator {    private ArrayList items;    private int position = 0;    public PancakeHouseIterator(ArrayList items) {        this.items = items;    }    @Override    public boolean hasNext() {        return position < items.size();    }    @Override    public MenuItem next() {        return items.get(position++);    }}

服务员类:

public class Waitress {    private Menu pancakeHouseMenu;    private 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); } private void printMenu(Iterator iterator) { while (iterator.hasNext()) { MenuItem menuItem = iterator.next(); System.out.print(menuItem.getName() + ", "); System.out.print(menuItem.getPrice() + " -- "); System.out.println(menuItem.getDescription()); } }}

      从上面的代码可以看出,服务员并没有针对具体的菜单进行编程,而是依赖于一个创建菜单迭代器的Menu接口和一个迭代器接口Iterator来进行编程的,服务员并不需要知道所传过来的是何种组装方式的菜单,而只需要使用实现这两个接口的菜单对象进行遍历即可,这就达到了将变化的依赖于多态而实现接口,将不变的依赖于接口的目的,从而实现服务员与菜单组装方式的分离。

      迭代器模式在Java类库的集合中随处可见,这里使用的Menu就相当于Java类库中的Iterable接口,其作用是创建一个迭代器对象,而Iterator接口和Java类库的Iterator接口基本一致。这里需要说明的是,实际上让一个类实现迭代器模式在为一个类增加功能的同时也增加了该类的维护负担,因为类的基本方法是高内聚的,所谓的内聚即是实现了一套相关的完整的功能,而迭代器接口实际上也是一套完整的相关的功能,因而让一个类实现迭代器模式隐含地为这个类增加了两套不那么“内聚”的两套功能,这就会导致该类在进行功能维护的时候需要兼顾双方。在Java类库中ArrayList和LinkedList中就有体现,其不仅提供了List所有的基本的remove方法,也提供了迭代器所需要实现的remove方法,为了实现两者的统一,其不得不作一些约定,比如遍历集合的时候不能调用该类基本的remove或者add等会更改该类结构的方法。

转载于:https://my.oschina.net/zhangxufeng/blog/794761

你可能感兴趣的文章
dell服务器硬盘的状态变成外来(foreign)
查看>>
redhat6.4更换centos 6 的 yum源
查看>>
jsquery问题
查看>>
深入了解android平台的jni---编译ffmpeg源码
查看>>
共享JSP部署后测试代码
查看>>
日常订阅的开发工具和服务——2018年
查看>>
linux下乱码问题及解决方式
查看>>
回车和换行有什么区别?很尴尬》》》
查看>>
Hibernate(十六)数据库事务与隔离级别
查看>>
laravel、lumen遇到的问题解决
查看>>
MYSQL-mysqlslap
查看>>
Cisco ASA5500解决内网用公网IP不能访问DMZ区服务器的
查看>>
Windows7常用命令
查看>>
crack-jar游戏之拉阔
查看>>
Java中的深拷贝和浅拷贝
查看>>
<JQuery>页面加载函数的三种写法
查看>>
大数据系列12:Hadoop2 – 全新的Hadoop
查看>>
Result相关
查看>>
关于scrolltop 兼容 IE6/7/8, Safari,FF的方法
查看>>
PRIu64宏—打印输出64位整型值
查看>>