开发之路(设计模式十:迭代器模式上)

有许多种方法可以把对象堆起来成为一个集合

好消息,当地的餐厅和煎饼屋合并了,但是两者实现的方式却不同,这就造成了分歧。让我们一起去看看把。
《开发之路(设计模式十:迭代器模式上)》
《开发之路(设计模式十:迭代器模式上)》

一个使用ArrayList集合,另一个使用数组实现,事情看起来确实棘手,我们创建一个女招待作为中间人来使用两个菜单的客户代码
《开发之路(设计模式十:迭代器模式上)》

这里就有个问题,我们在打印早餐和午餐的时候由于使用对象不同,Arraylist和数组,这样我们就要写两个for循环了,倘若后面还有新的对象加进来做晚餐呢?或许我们能想出一个办法,让他们的菜单实现一个相同的接口,我们是否可以试着封装多个遍历呢?步骤图如下
《开发之路(设计模式十:迭代器模式上)》
《开发之路(设计模式十:迭代器模式上)》

OK,看来迭代器模式帮助了我们,迭代器(iterator)依赖于迭代器接口。相关类图如下
《开发之路(设计模式十:迭代器模式上)》

想要在餐厅菜单中加入迭代器,我们先定义迭代器接口

package MenuItem;

/**
 * 迭代器接口
 * 
 * @author Joy
 * 
 */
public interface Iterator {
    // 知道是否还有更多元素
    boolean hasNext();

    // 返回下一个元素
    Object next();
}

然后先用DinerMenuIterator类去实现接口

package MenuItem;

/**
 * 实现迭代器
 * 
 * @author Joy
 * 
 */
public class DinerMenuIterator implements Iterator {
    MenuItem[] items;
    int position = 0;// 数组索引

    // 构造器初始化传入一个菜单项的数组当参数
    public DinerMenuIterator(MenuItem[] items) {
        this.items = items;
    }

    // 返回数组下一项,索引自+1
    @Override
    public Object next() {
        MenuItem menuItem = items[position];
        position += 1;
        return menuItem;
    }

    // 判断数组是否满了
    @Override
    public boolean hasNext() {
        if (position >= items.length || items[position] == null) {
            return false;
        }
        return true;
    }
}

我们有了菜单迭代器,利用它改写餐厅菜单,DineMenu类中这样写

package MenuItem;

/**
 * 对象村餐厅
 * 
 * @author Joy
 * 
 */
public class DineMenu {
    // 菜单总数
    static final int MAX_ITEMS = 6;
    // 菜单量
    int numberOfItems = 0;
    MenuItem[] menuItems;

    // 初始化数组,添加菜单内容
    public DineMenu() {
        menuItems = new MenuItem[MAX_ITEMS];
        addItem("素食BLT", "(煎)培根、生菜&西红柿并用面包做", true, 2.99);
        addItem("BLT", "培根、生菜&西红柿", false, 2.99);
        addItem("例汤", "一碗例汤、配土豆沙拉", false, 3.29);
        addItem("热狗", "热狗、酸菜、上盖芝士", false, 3.29);
        addItem("清蒸时蔬加糙米", "清蒸的蔬菜配糙米", 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("抱歉,菜单已满,不能添加菜单了");
        } else {
            // 菜单还没满还可以继续添加
            menuItems[numberOfItems] = menuItem;
            numberOfItems += 1;
        }
    }

    // 使用迭代器遍历菜单
    public Iterator createIterator() {
        return new DinerMenuIterator(menuItems);
    }
}

完整代码如下
《开发之路(设计模式十:迭代器模式上)》

迭代器接口

package MenuItem;

/**
 * 迭代器接口
 * 
 * @author Joy
 * 
 */
public interface Iterator {
    // 知道是否还有更多元素
    boolean hasNext();

    // 返回下一个元素
    Object next();
}

菜单类

package MenuItem;

/**
 * 对象村餐厅
 * 
 * @author Joy
 * 
 */
public class DineMenu {
    // 菜单总数
    static final int MAX_ITEMS = 6;
    // 菜单量
    int numberOfItems = 0;
    MenuItem[] menuItems;

    // 初始化数组,添加菜单内容
    public DineMenu() {
        menuItems = new MenuItem[MAX_ITEMS];
        addItem("素食BLT", "(煎)培根、生菜&西红柿并用面包做", true, 2.99);
        addItem("BLT", "培根、生菜&西红柿", false, 2.99);
        addItem("例汤", "一碗例汤、配土豆沙拉", false, 3.29);
        addItem("热狗", "热狗、酸菜、上盖芝士", false, 3.29);
        addItem("清蒸时蔬加糙米", "清蒸的蔬菜配糙米", 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("抱歉,菜单已满,不能添加菜单了");
        } else {
            // 菜单还没满还可以继续添加
            menuItems[numberOfItems] = menuItem;
            numberOfItems += 1;
        }
    }

    // 使用迭代器遍历菜单
    public Iterator createIterator() {
        return new DinerMenuIterator(menuItems);
    }
}

餐厅的实现以及接口

package MenuItem;

/**
 * 实现迭代器
 * 
 * @author Joy
 * 
 */
public class DinerMenuIterator implements Iterator {
    MenuItem[] items;
    int position = 0;// 数组索引

    // 构造器初始化传入一个菜单项的数组当参数
    public DinerMenuIterator(MenuItem[] items) {
        this.items = items;
    }

    // 返回数组下一项,索引自+1
    @Override
    public Object next() {
        MenuItem menuItem = items[position];
        position += 1;
        return menuItem;
    }

    // 判断数组是否满了
    @Override
    public boolean hasNext() {
        if (position >= items.length || items[position] == null) {
            return false;
        }
        return true;
    }
}
package MenuItem;

/**
 * 对象村餐厅
 * 
 * @author Joy
 * 
 */
public class DineMenu {
    // 菜单总数
    static final int MAX_ITEMS = 6;
    // 菜单量
    int numberOfItems = 0;
    MenuItem[] menuItems;

    // 初始化数组,添加菜单内容
    public DineMenu() {
        menuItems = new MenuItem[MAX_ITEMS];
        addItem("素食BLT", "(煎)培根、生菜&西红柿并用面包做", true, 2.99);
        addItem("BLT", "培根、生菜&西红柿", false, 2.99);
        addItem("例汤", "一碗例汤、配土豆沙拉", false, 3.29);
        addItem("热狗", "热狗、酸菜、上盖芝士", false, 3.29);
        addItem("清蒸时蔬加糙米", "清蒸的蔬菜配糙米", 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("抱歉,菜单已满,不能添加菜单了");
        } else {
            // 菜单还没满还可以继续添加
            menuItems[numberOfItems] = menuItem;
            numberOfItems += 1;
        }
    }

    // 使用迭代器遍历菜单
    public Iterator createIterator() {
        return new DinerMenuIterator(menuItems);
    }
}

同理煎饼屋的实现和接口

package MenuItem;

import java.util.ArrayList;

public class PancakeHouseIterator implements Iterator {
    ArrayList items;
    int position = 0;

    public PancakeHouseIterator(ArrayList items) {
        this.items = items;
    }

    @Override
    public Object next() {
        Object obj = items.get(position);
        position += 1;
        return obj;
    }

    @Override
    public boolean hasNext() {
        if (position >= items.size()) {
            return false;
        }
        return true;
    }
}
package MenuItem;

import java.util.ArrayList;

/**
 * 对象村煎饼屋菜单
 * 
 * @author Joy
 * 
 */
public class PancakeHouseMenu {
    ArrayList menuItems;

    public PancakeHouseMenu() {
        menuItems = new ArrayList();
        addItem("K&B薄煎饼早餐", "薄煎饼,清蛋和吐司", true, 2.99);
        addItem("薄煎饼早餐例餐", "薄煎饼,煎蛋和香肠", false, 2.99);
        addItem("蓝莓薄煎饼", "新鲜蓝莓和蓝莓糖浆做成的薄煎饼", false, 3.49);
        addItem("松饼", "可以选择蓝莓或草莓", true, 3.59);        

    }

    // 创建一个添加菜单方法
    public void addItem(String name, String description, boolean vegetarian,
            double price) {
        // 菜单项对象,并加入到ArrayList里
        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
        menuItems.add(menuItem);
    }

    //使用迭代器遍历菜单
    public Iterator createIterator(){
        return new PancakeHouseIterator(menuItems);
    }
}

女招待的实现

package MenuItem;
/**
 * 对象村的女招待
 * 
 * @author Joy
 * 
 */
public class Waitress {
    //创建两个餐厅对象的引用
    PancakeHouseMenu pancakeHouseMenu;
    DineMenu dineMenu;

    // 初始化两个菜单
    public Waitress(PancakeHouseMenu pancakeHouseMenu, DineMenu dineMenu) {
        this.dineMenu = dineMenu;
        this.pancakeHouseMenu = pancakeHouseMenu;
    }

    public void printMenu() {
        // 为每一个菜单创建一个迭代器
        Iterator pancakeitIterator = pancakeHouseMenu.createIterator();
        Iterator dinerIterator = dineMenu.createIterator();
        System.out.println("Menu\n=======\nBreakFast");
        // 调用下面重载的方法
        printMenus(pancakeitIterator);
        System.out.println("\nLunch");
        // 调用下面重载的方法
        printMenus(dinerIterator);
    }

    // 重载一个printMenu()方法
    // 使用迭代器(一次循环即可)来遍历菜单项并打印出来,只调用Iterator接口
    public void printMenus(Iterator iterator) {
        while (iterator.hasNext()) {
            // 取得下一项
            MenuItem menuItem = (MenuItem) iterator.next();
            System.out.print(menuItem.getName() + ", ");
            System.out.print(menuItem.getPrice() + ", ");
            System.out.println(menuItem.getDescription());
        }
    }
}

测试类

package TestMain;
import MenuItem.DineMenu;
import MenuItem.PancakeHouseMenu;
import MenuItem.Waitress;

public class MenuTestDrive {
    public static void main(String[] args) {
        PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();        
        DineMenu dineMenu = new DineMenu();
        /**
         *两个菜单都实现一样的方法,但是并没有实现相同的接口,
         *女招待还是要依赖两个具体实现的菜单类
         *后面就要修改这里
         *
         */
        Waitress waitress = new Waitress(pancakeHouseMenu, dineMenu);
        waitress.printMenu();
    }
}

效果图如下
《开发之路(设计模式十:迭代器模式上)》

很巧妙的将两者迭代取出来了。但两者实现的接口却完全一样,这里其实还可以抽象出来成一个共同接口。

感谢你看到这里,迭代器模式上部分到这里就结束了,本人文笔随便,若有不足或错误之处望给予指点,90度弯腰~~~很快我会补全这个内容,生命不息,编程不止!

参考书籍《Head First设计模式》
    原文作者:设计模式
    原文地址: https://segmentfault.com/a/1190000011422478
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞