设计模式 —— 迭代器模式(Iterator Pattern)

来源:互联网 发布:jordan淘宝官方旗舰店 编辑:程序博客网 时间:2024/05/16 00:38

迭代器模式(Iterator Pattern)

概念:

定义:迭代器模式 提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。


迭代器模式是一种简单常见的设计模式,在我们使用编程语言中的集合容器都会有迭代器。


组成:

迭代器模式

Aggregate(抽象聚合):共同的接口供所有的聚合使用。

ConcreteAggregate(聚合):持有一个对象的集合,并实现 createIterator 方法,返回集合的迭代器。

Iterator(抽象迭代器接口):包含所有迭代器都必须实现的方法。

ConcreteIterator(具体迭代器):实现了迭代器接口的具体迭代器。


例子:

现有两家超市,一家为水果超市,一家为零食超市。他们分别请了两位编程人员帮他们实现打印品种清单程序。结果第一家编程人员用数组集合来存储不同的水果,第二家编程人员用 ArrayList 集合来存储零食种类。如下:

物品类:

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

水果超市类:

public class FruitSupermarket {    ArrayList menuItems;    public FruitSupermarket() {        menuItems = new ArrayList();        //添加水果        addItem("苹果", "红色的", 1.99);        addItem("香蕉", "黄色的", 2.00);        addItem("橙子", "横色的", 3.12);    }    public void addItem(String name, String description, double price) {        Item item = new Item(name, description, price);        menuItems.add(item);    }    public ArrayList getMenuItems() {        return menuItems;    }}

零食超市类:

public class SnacksSupermarket {    static final int MAX_ITEMS = 6;    int numberOfItems = 0;    Item[] menuItems;    public SnacksSupermarket() {        menuItems = new Item[MAX_ITEMS];        //添加零食        addItem("牛奶", "伊利", 2.24);        addItem("糖", "阿尔卑斯", 5.12);        addItem("巧克力", "金蒂", 1.23);    }    public void addItem(String name, String description, double price) {        Item item = new Item(name, description, price);        if (numberOfItems >= MAX_ITEMS) {            System.out.println("抱歉,清单已满...");        } else {            menuItems[numberOfItems] = item;            numberOfItems += 1;        }    }    public Item[] getMenuItems() {        return menuItems;    }}

现在假设两家超市合并了,我们要遍历两家超市的清单。

public class Supermarket {    FruitSupermarket fruitSupermarket;    SnacksSupermarket snacksSupermarket;    public Supermarket() {        fruitSupermarket = new FruitSupermarket();        snacksSupermarket = new SnacksSupermarket();    }    //遍历菜单方法,内部分别包含两家超市的遍历。    public void printMenu() {        ArrayList fruitItems = fruitSupermarket.getMenuItems();        Item[] snacksItems = snacksSupermarket.getMenuItems();        //遍历水果超市        System.out.println("fruitItem:");        for (int i = 0; i < fruitItems.size(); ++i) {            Item item = (Item) fruitItems.get(i);            System.out.print("name:" + item.getName());            System.out.print(" description:" + item.getDescription());            System.out.println(" price:" + item.getPrice());        }        //遍历零食超市        System.out.println("\nsnacksItem:");        for (int i = 0; i < snacksSupermarket.getNumberOfItems(); ++i) {            Item item = snacksItems[i];            System.out.print("name:" + item.getName());            System.out.print(" description:" + item.getDescription());            System.out.println(" price:" + item.getPrice());        }    }    public static void main(String[] args) {        Supermarket supermarket = new Supermarket();        supermarket.printMenu();    }}

迭代器模式


如果将来再次合并超市又必须修改代码,增加一个循环,我们可以发现上述代码成了 面向实现 编程而不是 面向接口
我们来通过 迭代器模式 改进这个类。


先将两个超市类增加 createIterator() 方法,返回内部集合的迭代器。

由于 ArrayList 本身有迭代器,我们直接返回即可。

    //省略原本类的方法    public Iterator createIterator() {        return menuItems.iterator();    }

但零食超市中的数组集合没有迭代器,我们自己实现一个。

//Java 提供了迭代器接口,我们直接实现即可public class SnacksIterator implements Iterator {    Item[] menuItems;    int position = 0;    public SnacksIterator(Item[] menuItems) {        this.menuItems = menuItems;    }    //判断是否有下一个元素方法    public boolean hasNext() {        if (position >= menuItems.length || menuItems[position] == null) {            return false;        }else {            return true;        }    }    //返回下一个对象方法    public Object next() {        Item menuitem = menuItems[position];        position += 1;        return menuitem;    }}
    //...省略原本类和方法    public Iterator createIterator() {        return new SnacksIterator(menuItems);    }

超市类:

public class Supermarket {    FruitSupermarket fruitSupermarket;    SnacksSupermarket snacksSupermarket;    public Supermarket() {        fruitSupermarket = new FruitSupermarket();        snacksSupermarket = new SnacksSupermarket();    }    //由于实现了统一的接口,再次添加我们继续创建对应的迭代器类,加入 printMenu 即可。    public void printMenu() {        //我们也可以将所有的清单加入集合中,这样下面的代码也不用改变了。        Iterator fruitIterator = fruitSupermarket.createIterator();        Iterator snacksIterator = snacksSupermarket.createIterator();        System.out.println("FruitSupermarket");        printMenu(fruitIterator);        System.out.println("\nSnacksSupermarket");        printMenu(snacksIterator);    }    private void printMenu(Iterator iterator) {        while (iterator.hasNext()) {            Item item = (Item) iterator.next();            System.out.print("name:" + item.getName());            System.out.print(" description:" + item.getDescription());            System.out.println(" price:" + item.getPrice());        }    }    public static void main(String[] args) {        Supermarket supermarket = new Supermarket();        supermarket.printMenu();    }}

迭代器模式


适用场景:

  • 访问一个聚合对象的内容而无需暴露它的内部表示。
  • 需要为聚合对象提供多种遍历方式。
  • 为遍历不同的聚合结构提供一个统一的接口 (即, 支持多态迭代)

补充:设计原则

单一设计原则:一个类应该只有一个引起变化的原因
我们应该避免类内的改变,因为修改代码很容易造成许多潜在的错误。如果一个类具有两个改变的原因,那么类变化的几率就很大了,并且当它真的改变时,我们的设计中会有两方面受到影响。

当一个模块或一个类被设计成只支持一组相关的功能时,我们说它具有高内聚。反之,当被设计成支持一组不相关的功能时,我们说它具有低内聚。

0 0
原创粉丝点击