关闭

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

标签: 设计模式iterator迭代器
296人阅读 评论(0) 收藏 举报
分类:

迭代器模式(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

猜你在找
【直播】机器学习&数据挖掘7周实训--韦玮
【套餐】系统集成项目管理工程师顺利通关--徐朋
【直播】3小时掌握Docker最佳实战-徐西宁
【套餐】机器学习系列套餐(算法+实战)--唐宇迪
【直播】计算机视觉原理及实战--屈教授
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之矩阵--黄博士
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之凸优化--马博士
【套餐】Javascript 设计模式实战--曾亮
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:212729次
    • 积分:3904
    • 等级:
    • 排名:第8084名
    • 原创:144篇
    • 转载:25篇
    • 译文:4篇
    • 评论:146条
    博客专栏
    Study