设计模式之迭代器与组合模式

Posted dimple91

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之迭代器与组合模式相关的知识,希望对你有一定的参考价值。

因为这系列篇幅较长,所以在这里也不进行任何铺垫,直奔主题去啦。

利用组合设计菜单

我们要如何在菜单上应用组合模式呢?一开始,我们需要创建一个组件接口来作为菜单和菜单项的共同接口,让我们能够用统一的做法来处理菜单和菜单项。换句话说,我们可以针对菜单或菜单项调用相同的方法。

让我们从头来看看如何让菜单能够符合组合模式的结构:

技术图片

实现菜单组件

好了,我们开始编写菜单组件的抽象类;请记住,菜单组件的角色是为叶节点和组合节点提供一个共同的接口。

public abstract class MenuComponent 
   
    public void add(MenuComponent menuComponent) 
        throw new UnsupportedOperationException();
    
    public void remove(MenuComponent menuComponent) 
        throw new UnsupportedOperationException();
    
    public MenuComponent getChild(int i) 
        throw new UnsupportedOperationException();
    
  
    public String getName() 
        throw new UnsupportedOperationException();
    
    public String getDescription() 
        throw new UnsupportedOperationException();
    
    public double getPrice() 
        throw new UnsupportedOperationException();
    
    public boolean isVegetarian() 
        throw new UnsupportedOperationException();
    

    public abstract Iterator<MenuComponent> createIterator();
 
    public void print() 
        throw new UnsupportedOperationException();
    

让我们来看菜单类。别忘了,这是组合类图里的叶类,它实现组合内元素的行为。

public class MenuItem extends MenuComponent 
 
    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 Iterator<MenuComponent> createIterator() 
        return new NullIterator();
    
 
    public void print() 
        System.out.print("  " + getName());
        if (isVegetarian()) 
            System.out.print("(v)");
        
        System.out.println(", " + getPrice());
        System.out.println("     -- " + getDescription());
    

我们已经有了菜单项,还需要组合类,这就是我们叫做菜单的。别忘了,此组合类可以持有菜单项或其他菜单。

public class Menu extends MenuComponent 
    Iterator<MenuComponent> iterator = null;
    ArrayList<MenuComponent> menuComponents = new ArrayList<MenuComponent>();
    String name;
    String description;
  
    public Menu(String name, String description) 
        this.name = name;
        this.description = description;
    
 
    public void add(MenuComponent menuComponent) 
        menuComponents.add(menuComponent);
    
 
    public void remove(MenuComponent menuComponent) 
        menuComponents.remove(menuComponent);
    
 
    public MenuComponent getChild(int i) 
        return menuComponents.get(i);
    
 
    public String getName() 
        return name;
    
 
    public String getDescription() 
        return description;
    

  
    public Iterator<MenuComponent> createIterator() 
        if (iterator == null) 
            iterator = new CompositeIterator(menuComponents.iterator());
        
        return iterator;
    
 
 
    public void print() 
        System.out.print("\n" + getName());
        System.out.println(", " + getDescription());
        System.out.println("---------------------");
    

因为菜单是一个组合,包含了菜单项和其他的菜单,所以它的print()应该打印出它所包含的一切。如果它不这么做,我们就必须遍历整个组合的每个节点,然后将每一项打印出来。这么一来,也就失去了使用组合结构的意义

所以,print还得进行优化,如下:

public void print() 
    System.out.print("\n" + getName());
    System.out.println(", " + getDescription());
    System.out.println("---------------------");
 
    Iterator<MenuComponent> iterator = menuComponents.iterator();
    while (iterator.hasNext()) 
        MenuComponent menuComponent = iterator.next();
        menuComponent.print();
    

看到上面了没,我们用了迭代器。用它遍历所有菜单组件,遍历过程中,可能遇到其他菜单,或者是遇到菜单项。由于菜单和菜单项都实现了print,那我们只要调用print即可。

开始测试数据之前,我们了解一下,在运行时菜单组合是什么样的:

技术图片

开始运行我们的测试程序啦:

public class MenuTestDrive 
    public static void main(String args[]) 

        MenuComponent pancakeHouseMenu = 
            new Menu("PANCAKE HOUSE MENU", "Breakfast");
        MenuComponent dinerMenu = 
            new Menu("DINER MENU", "Lunch");
        MenuComponent cafeMenu = 
            new Menu("CAFE MENU", "Dinner");
        MenuComponent dessertMenu = 
            new Menu("DESSERT MENU", "Dessert of course!");
  
        MenuComponent allMenus = new Menu("ALL MENUS", "All menus combined");
  
        allMenus.add(pancakeHouseMenu);
        allMenus.add(dinerMenu);
        allMenus.add(cafeMenu);
  
        pancakeHouseMenu.add(new MenuItem(
            "K&B's Pancake Breakfast", 
            "Pancakes with scrambled eggs, and toast", 
            true,
            2.99));
        pancakeHouseMenu.add(new MenuItem(
            "Regular Pancake Breakfast", 
            "Pancakes with fried eggs, sausage", 
            false,
            2.99));
        pancakeHouseMenu.add(new MenuItem(
            "Blueberry Pancakes",
            "Pancakes made with fresh blueberries, and blueberry syrup",
            true,
            3.49));
        pancakeHouseMenu.add(new MenuItem(
            "Waffles",
            "Waffles, with your choice of blueberries or strawberries",
            true,
            3.59));

        dinerMenu.add(new MenuItem(
            "Vegetarian BLT",
            "(Fakin') Bacon with lettuce & tomato on whole wheat", 
            true, 
            2.99));
        dinerMenu.add(new MenuItem(
            "BLT",
            "Bacon with lettuce & tomato on whole wheat", 
            false, 
            2.99));
        dinerMenu.add(new MenuItem(
            "Soup of the day",
            "A bowl of the soup of the day, with a side of potato salad", 
            false, 
            3.29));
        dinerMenu.add(new MenuItem(
            "Hotdog",
            "A hot dog, with saurkraut, relish, onions, topped with cheese",
            false, 
            3.05));
        dinerMenu.add(new MenuItem(
            "Steamed Veggies and Brown Rice",
            "A medly of steamed vegetables over brown rice", 
            true, 
            3.99));
 
        dinerMenu.add(new MenuItem(
            "Pasta",
            "Spaghetti with Marinara Sauce, and a slice of sourdough bread",
            true, 
            3.89));
   
        dinerMenu.add(dessertMenu);
  
        dessertMenu.add(new MenuItem(
            "Apple Pie",
            "Apple pie with a flakey crust, topped with vanilla icecream",
            true,
            1.59));
        dessertMenu.add(new MenuItem(
            "Cheesecake",
            "Creamy New York cheesecake, with a chocolate graham crust",
            true,
            1.99));
        dessertMenu.add(new MenuItem(
            "Sorbet",
            "A scoop of raspberry and a scoop of lime",
            true,
            1.89));

        cafeMenu.add(new MenuItem(
            "Veggie Burger and Air Fries",
            "Veggie burger on a whole wheat bun, lettuce, tomato, and fries",
            true, 
            3.99));
        cafeMenu.add(new MenuItem(
            "Soup of the day",
            "A cup of the soup of the day, with a side salad",
            false, 
            3.69));
        cafeMenu.add(new MenuItem(
            "Burrito",
            "A large burrito, with whole pinto beans, salsa, guacamole",
            true, 
            4.29));
 
        Waitress waitress = new Waitress(allMenus);
   
        waitress.printVegetarianMenu();
 
    

结果这里就不附上了,请大家自行去跑代码实现吧。相信你们又对组合模式也已经有了一个大概了吧。下一篇,还有更犀利的,组合迭代器等着我们。小编马上回去搞起来,安排上。

爱生活,爱学习,爱感悟,爱挨踢

技术图片

以上是关于设计模式之迭代器与组合模式的主要内容,如果未能解决你的问题,请参考以下文章

深入浅出设计模式之模板方法模式迭代器模式组合模式

迭代器模式和组合模式

Head First设计模式——组合模式

Head First设计模式——组合模式

迭代器和组合模式

《Head First 设计模式》中组合迭代器重复打印的bug的两种解决方案