迭代器模式

1,定义:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
2,类图及角色介绍。
这里写图片描述
Aggregate:聚合接口,有一个createIterator()接口方法,所有的具体聚合类都实现这个接口并实现接口方法;
ConcreteAggregate:具体聚合类,持有一个对象的集合,实现createIterator()方法,利用此方法返回集合的具体迭代器;
Iterator:这是所有的迭代器都必须实现的接口,它包含一些方法,利用这些方法可以在集合元素之间游走;
ConcreteIterator:具体迭代器,真正负责集合的遍历。
Client:客户端。客户端只需关心聚合接口和迭代器接口,客户端持有聚合接口的引用,利用构造方法取得聚合对象,然后调用聚合对象的creatIterator()方法得到迭代器,然后调用迭代器的各个方法就可以遍历集合了,这样,客户端不需要知道具体是怎么遍历的,只知道使用那个迭代器就可以正确遍历。

3,一个小例子
(1)创建一个聚合接口(菜单接口)

/**
 * 菜单接口(聚合类接口)
 */
public interface Menu {
    // 创建迭代器
    public Iterator createIterator();
}

(2)创建菜单项(简单Java类)

/**
 * 菜单项(一个简单Java类)
 */
public class MenuItem {
    String name;
    String description;
    boolean vegetarian;
    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 double getPrice() {
        return price;
    }
    public boolean isVegetarian() {
        return vegetarian;
    }
    public String toString() {
        return (name + ", $" + price + "\n   " + description);
    }
}

(3)创建两个具体聚合类(餐厅菜单,煎饼屋菜单)

/**
 * 餐厅菜单
 */
public class DinerMenu implements Menu {
    static final int MAX_ITEMS = 6;
    int numberOfItems = 0;
    // 根据返回的具体迭代器的请求参数类型确定该属性的类型
    // 如返回的是一个DinerMenuIterator,它需要一个数组类型的参数,那么这个属性就是数组类型
    MenuItem[] menuItems;
    public DinerMenu() {
        menuItems = new MenuItem[MAX_ITEMS];
        addItem("西红柿炒鸡蛋", "要用到西红柿,鸡蛋,糖,葱", false, 10.00);
        addItem("辣椒炒肉", "要用很辣的辣椒和瘦肉炒才好吃", false, 10.00);
        addItem("木耳肉丝", "用新鲜的木耳,和切成丝的肉一起炒", false, 10.00);
        addItem("酸豆角炒肉", "酸豆角切成小段小段,加上瘦肉和辣椒", false, 10.00);
    }
    public void addItem(String name, String description, 
                         boolean vegetarian, double price) 
    {
        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
        if (numberOfItems >= MAX_ITEMS) {
            System.err.println("Sorry, menu is full!  Can't add item to menu");
        } else {
            menuItems[numberOfItems] = menuItem;
            numberOfItems = numberOfItems + 1;
        }
    }
    public MenuItem[] getMenuItems() {
        return menuItems;
    }
    // 返回一个具体的迭代器DinerMenuIterator
    public Iterator createIterator() {
        return new DinerMenuIterator(menuItems);
    }
}
/**
 * 煎饼屋菜单
 */
public class PancakeHouseMenu implements Menu {
    // 根据返回的具体迭代器的请求参数类型确定该属性的类型
    // 如返回的是一个PancakeHouseMenuIterator,它需要一个List集合类型的参数,那么这个属性就是list集合类型
    ArrayList<MenuItem> menuItems;
    // 构造方法加载菜单项,供迭代器进行遍历
    public PancakeHouseMenu() {
        menuItems = new ArrayList<MenuItem>();
        addItem("葱花饼", "好吃", false, 2.99);
        addItem("酱香饼",  "不贵", false, 2.99);
        addItem("酸菜饼", "物美", false, 3.49);
        addItem("鸡蛋饼", "价廉", false, 3.59);
    }
    public void addItem(String name, String description, boolean vegetarian,double price){
        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
        menuItems.add(menuItem);
    }
    public ArrayList<MenuItem> getMenuItems() {
        return menuItems;
    }
    // 该方法返回一个煎饼屋菜单迭代器
    public Iterator createIterator() {
        return new PancakeHouseMenuIterator(menuItems);
    }
    public String toString() {
        return "Objectville Pancake House Menu";
    }
}

(4)创建一个迭代器接口

/**
 * 迭代器接口
 */
public interface Iterator {
    // 是否还有下一个
    boolean hasNext();
    // 返回菜单项
    MenuItem next();
}

(5)创建两个具体迭代器(餐厅菜单迭代器,煎饼屋菜单迭代器)

/**
 * 餐厅菜单迭代器
 */
public class DinerMenuIterator implements Iterator {
    MenuItem[] items;
    int position = 0;
    public DinerMenuIterator(MenuItem[] items) {
        this.items = items;
    }
    public MenuItem next() {
        MenuItem menuItem = items[position];
        position = position + 1;
        return menuItem;
    }
    public boolean hasNext() {
        if (position >= items.length || items[position] == null) {
            return false;
        } else {
            return true;
        }
    }
}
/**
 * 煎饼屋菜单迭代器
 */
public class PancakeHouseMenuIterator implements Iterator {
    ArrayList<MenuItem> items;
    int position = 0;
    public PancakeHouseMenuIterator(ArrayList<MenuItem> items) {
        this.items = items;
    }
    // 迭代器方法,遍历集合中的元素
    public MenuItem next() {
        MenuItem item = items.get(position);
        position = position + 1;
        return item;
    }
    // 迭代器方法,判断是否还有下一个元素
    public boolean hasNext() {
        if (position >= items.size()) {
            return false;
        } else {
            return true;
        }
    }
}

(6)创建客户端(一个女招待)

/**
 * 女招待(客户端)(只需关心菜单接口和迭代器接口。其实感觉女招待只要和
 * 菜单接口打交道就行了,因为传入什么菜单,也就确定了用什么迭代器)
 */
public class Waitress {
    // 客户端持有各个菜单的引用
    Menu pancakeHouseMenu;
    Menu dinerMenu;
    // 通过构造方法获取需要的菜单(什么菜单都行,只要实现了菜单接口,这样女招待
    // 就不需要知道菜单的具体实现了,成功解耦)
    public Waitress(Menu pancakeHouseMenu, Menu dinerMenu) {
        this.pancakeHouseMenu = pancakeHouseMenu;
        this.dinerMenu = dinerMenu;
    }
    // 打印菜单
    public void printMenu() {
        // 通过传入的菜单获得相应的迭代器(具体是什么迭代器不知道,只知道实现了
        // 菜单接口的接口方法createIterator()要返回一个迭代器的超类)
        Iterator pancakeIterator = pancakeHouseMenu.createIterator();
        Iterator dinerIterator = dinerMenu.createIterator();
        // 打印菜单
        System.out.println("煎饼屋菜单:");
        printMenu(pancakeIterator);
        System.out.println("餐厅菜单:");
        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());
        }
    }
}

(7)创建测试类

public class MenuTestDrive {
    public static void main(String args[]) {
        // 创建两个菜单
        PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
        DinerMenu dinerMenu = new DinerMenu();
        // 创建一个女招待
        Waitress waitress = new Waitress(pancakeHouseMenu, dinerMenu);
        // 女招待打印菜单
        waitress.printMenu();
    }
}

(8)输出

煎饼屋菜单:
葱花饼, 2.99 -- 好吃
酱香饼, 2.99 -- 不贵
酸菜饼, 3.49 -- 物美
鸡蛋饼, 3.59 -- 价廉
餐厅菜单:
西红柿炒鸡蛋, 2.99 -- 要用到西红柿,鸡蛋,糖,葱
辣椒炒肉, 2.99 -- 要用很辣的辣椒和瘦肉炒才好吃
木耳肉丝, 3.29 -- 用新鲜的木耳,和切成丝的肉一起炒
酸豆角炒肉, 3.05 -- 酸豆角切成小段小段,加上瘦肉和辣椒

4,小结
迭代器作用:如果你有一个统一的方法访问聚合中的每一个对象,你就可以编写多态的代码和这些聚合搭配使用。如同例子中的printMenu()方法一样,只要有了迭代器,这个方法根本不管菜单项是由数组还是由ArrayList来保存的。

迭代器模式把在元素之间游走的责任交给迭代器,而不是聚合对象。这不仅让聚合的接口和实现变得简洁,也可以让聚合更专注在它所应该专注的事情上面(也就是管理对象集合),而不必去理会遍历的事情。

这也很容易扩展,如果要加入一个新的菜单,而这个菜单是由另一个数据结构保存的,那么我们也只是再写一个遍历该数据结构的迭代器,且该迭代器实现迭代器接口,然后让新菜单实现菜单接口,再修改一下女招待的构造方法就行了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值