设计模式:迭代器模式

  迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而不是暴露其内部的表示。把游走的任务放在迭代器上,而不是聚合上,这样就简化了聚合的接口,也让责任各得其所。

  场景:有一家早餐店和一家晚餐店合并成一家餐厅,现对两个餐厅的菜单进行合并,两家菜单都一样,有name,decription,price,vegetarian属性,而早餐店的菜单是存放在List集合中,晚餐店的菜单存放在数组中,并且对晚餐的菜单数量进行了限制,不想品种太多。这时候如果服务员需要打印菜单,就可以写for循环遍历List,并转换成菜单类输出,同样,用for循环遍历数组,那如果有十几家餐厅合并呢,那不是要写十个for循环了吗?这时候,我们就来看看迭代器模式怎么解决这问题的。

  首先,我们创建一个菜单项类,表示具体的食物

//菜单项类
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;
    }
  //  get方法  
}

  接着我们创建一个迭代器接口,并且让实现早餐迭代器和晚餐迭代器

//迭代器接口
public interface Iterator {
    //判断是否还有元素
    boolean hasNext();
    //返回下一个元素
    Object next();
}

//早餐类迭代器
public class PancakeHouseMenuIterator implements Iterator{
    ArrayList items;
    int position = 0;
    
    public  PancakeHouseMenuIterator(ArrayList items){
        this.items = items;
    }
    
    @Override
    public Object next(){
        MenuItem menuItem = (MenuItem)items.get(position);
        position ++;
        return menuItem;
    }

    @Override
    public boolean hasNext() {
       if(position >= items.size() || items.get(position) == null){
           return false;
       }
       else{
           return true;
       }
    }
}

//晚餐菜单的迭代器
public class DinerMenuIterator implements Iterator{
    MenuItem[] items;
    //记录当前数组变量的位置
    int position = 0;
    
    public  DinerMenuIterator(MenuItem[] items){
        this.items = items;
    }
    
    @Override
    public Object next(){
        MenuItem menuItem = items[position];
        position ++;
        return menuItem;
    }

    @Override
    public boolean hasNext() {
       if(position >= items.length || items[position] == null){
           return false;
       }
       else{
           return true;
       }
    }
}

  然后我们创建菜单接口,让早餐店和晚餐点的菜单实现这个接口

//由于早餐店菜单的方法和晚餐店菜单的方法很类似,所以我们可以定义一个接口来减少Waitress与具体类的依赖,比较我们要针对接口编程,而不针对实现编程
//菜单接口
public interface Menu {
    public void addItem(String name,String description,boolean vegetarian,double price);
    public Iterator createIterator();
}

public class DinerMenu implements Menu{
    //限制晚餐菜单品种个数
    static final int MAX_ITEMS = 6;
    //记录菜单项的长度
    int numberOfItems = 0;
    MenuItem[] menuItems;
    
    public DinerMenu(){
        menuItems = new MenuItem[MAX_ITEMS];
        
        addItem("火焰牛排","用火焰点缀的牛排",false,98.0);
        addItem("红烧牛肉面","香辣可口的牛肉面",false,23.5);
        addItem("土豆丝盖浇饭","酸酸辣辣的土豆丝",true,10.0);
        addItem("蔬菜沙拉","新鲜蔬菜拌上沙拉酱",true,9.0);
        
    }
    
    @Override
    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("菜单满了,不能添加了!");
        }
        else{
            menuItems[numberOfItems] = menuItem;
            numberOfItems = numberOfItems + 1;
        }
    }

    //加入一个方法创建一个DinerMenuIterator并返回给客户
    @Override
    public Iterator createIterator(){
        return new DinerMenuIterator(menuItems);
    }
}

//早餐类
public class PancakeHouseMenu implements Menu {
    
    ArrayList menuItems;
    
    public PancakeHouseMenu(){
        //初始化早餐菜单
        menuItems = new ArrayList();
        
        addItem("里脊鸡蛋饼","鸡蛋和面粉融合并煎烤而成",false,8.0);
        addItem("青菜包","新鲜青菜与面粉融合",true,1.5);
        addItem("豆腐包","丝滑豆腐与面粉融合",true,1.5);
        addItem("豆浆","现磨黄豆",true,2.5);
    }
    
    @Override
    public void addItem(String name,String description,boolean vegetarian,double price){
        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
        menuItems.add(menuItem);
    }
    
    //加入一个方法创建一个PancakeHouseMenuIterator并返回给客户
    @Override
       public Iterator createIterator(){
           return new PancakeHouseMenuIterator(menuItems);
       }
}

  最后我们还要创建一个服务员类

//服务员类,用来合并菜单
public class Waitress {
    Menu pancakeHouseMenu;
    Menu dinerMenu;
    
    //我们其实可以把菜单存在一个List传过来,这里为了方便就直接写两个菜单参数了
    public Waitress(Menu pancakeHouseMenu,Menu dinerMenu){
        this.pancakeHouseMenu = pancakeHouseMenu;
        this.dinerMenu = dinerMenu;
    }
    
    public void  printMenu(){
        Iterator pancakeIterator = pancakeHouseMenu.createIterator();
        Iterator dinerIterator = dinerMenu.createIterator();
        System.out.println("早餐的菜单:");
        printMenu(pancakeIterator);
        System.out.println();
        System.out.println("晚餐菜单:");
        printMenu(dinerIterator);
        
    }
    
    //通过迭代器模式,我们只需要一个循环就可以实现那些list、数组、map等这些存储的遍历了
    public void printMenu(Iterator iterator){
        while(iterator.hasNext()){
            MenuItem menuItem = (MenuItem)iterator.next();
            System.out.println("名称:" + menuItem.getName() + ",介绍:" + menuItem.getDescription() + ",是否素菜:" +menuItem.isVegetarian() + ",价格:" + menuItem.getPrice());
        }
    }
}

  好了让我们来编写测试类来进行测试下

public class Test {
    public static void main(String[] args) {
        PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
        DinerMenu dinerMenu = new DinerMenu();
        
        //创建服务员,把菜单传给她
        Waitress waitress = new Waitress(pancakeHouseMenu, dinerMenu);
        
        //打印菜单
        waitress.printMenu();
    }
}

  运行结果如下:

     

  这就是迭代器模式了,就不需要我们写那么多类似的for循环了。

  下一节:组合模式

作者:哀&RT
出处:博客园哀&RT的技术博客--http://www.cnblogs.com/Tony-Anne/
您的支持是对博主最大的鼓励,感谢您的认真阅读。
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
原文地址:https://www.cnblogs.com/Tony-Anne/p/6525513.html