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

迭代器模式(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
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏天的技术博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值