/** * * * 组合模式: 可以使组合对象形成树形结构,以表现出整体/部分的结构,并提供一致的方法访问整体和局部 * 组合结构内任意对象称为组件,组件可以是组合,也可以是叶节点 * 客户可以将对象的集合以及个别的对象一视同仁 * * 运用了递归迭代的思想 * * 外部迭代器必须维护它在遍历中的位置,以便外部客户可以通过调用hasNext和next方法来驱动遍历 * * 组合和叶节点都属于组件,只是两者的角色定位不同而已 * 组合--拥有一群子元素 * 叶节点--无子元素 * * @author Administrator * */
菜单组件
package com.undergrowth.composition; import java.util.Iterator; /** * * * 组合模式: 可以使组合对象形成树形结构,以表现出整体/部分的结构,并提供一致的方法访问整体和局部 * 组合结构内任意对象称为组件,组件可以是组合,也可以是叶节点 * 客户可以将对象的集合以及个别的对象一视同仁 * * 运用了递归迭代的思想 * * 外部迭代器必须维护它在遍历中的位置,以便外部客户可以通过调用hasNext和next方法来驱动遍历 * * 组合和叶节点都属于组件,只是两者的角色定位不同而已 * 组合--拥有一群子元素 * 叶节点--无子元素 * * @author Administrator * */ public abstract class MenuComponent { /** * 提供的默认实现 让子元素决定是否重写 * * @param 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 float getPrice() { throw new UnsupportedOperationException(); } public String getDescription() { throw new UnsupportedOperationException(); } public boolean isVegetarian() { throw new UnsupportedOperationException(); } public void print() { throw new UnsupportedOperationException(); } public abstract Iterator createIterator(); }
组合 菜单-可拥有菜单项
package com.undergrowth.composition; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Menu extends MenuComponent { List<MenuComponent> menus = new ArrayList<>(); String name; String description; public Menu(String name, String description) { super(); this.name = name; this.description = description; } @Override public void add(MenuComponent menuComponent) { // TODO Auto-generated method stub menus.add(menuComponent); } @Override public void remove(MenuComponent menuComponent) { // TODO Auto-generated method stub menus.remove(menuComponent); } @Override public MenuComponent getChild(int i) { // TODO Auto-generated method stub return menus.get(i); } @Override public void print() { // TODO Auto-generated method stub System.out.println(getName()+","+getDescription()); System.out.println("==============================="); Iterator iteratorMenu=menus.iterator(); //迭代递归打印方式 while (iteratorMenu.hasNext()) { MenuComponent menuComponent = (MenuComponent) iteratorMenu.next(); menuComponent.print(); } System.out.println("=============================================================="); } @Override public String getName() { // TODO Auto-generated method stub return name; } @Override public String getDescription() { // TODO Auto-generated method stub return description; } /** * 外部迭代器 使用堆栈记录当前迭代位置 */ @Override public Iterator createIterator() { // TODO Auto-generated method stub return new CompositionIterator(menus.iterator()); } }
叶子节点 菜单项
package com.undergrowth.composition; import java.util.Iterator; public class MenuItem extends MenuComponent { String name; float price; String description; boolean vegetarian; public MenuItem(String name, float price, String description, boolean vegetarian) { super(); this.name = name; this.price = price; this.description = description; this.vegetarian = vegetarian; } public MenuItem(String name, String description, boolean vegetarian, double price) { super(); this.name = name; this.price = (float) price; this.description = description; this.vegetarian = vegetarian; } @Override public String getName() { // TODO Auto-generated method stub return name; } @Override public float getPrice() { // TODO Auto-generated method stub return price; } @Override public String getDescription() { // TODO Auto-generated method stub return description; } @Override public boolean isVegetarian() { // TODO Auto-generated method stub return vegetarian; } @Override public void print() { // TODO Auto-generated method stub System.out.println(toString()); } @Override public String toString() { return "MenuItem [name=" + name + ", price=" + price + ", description=" + description + ", vegetarian=" + vegetarian + "]"; } @Override public Iterator createIterator() { // TODO Auto-generated method stub return new NullIterator(); } }
package com.undergrowth.composition; import java.util.Iterator; import java.util.Stack; /** * 外部迭代器 使用堆栈记录当前迭代的元素 * @author Administrator * */ public class CompositionIterator implements Iterator { //使用堆栈 迭代树形结构 Stack stack=new Stack<>(); public CompositionIterator(Iterator iterator) { // TODO Auto-generated constructor stub stack.push(iterator); } @Override public boolean hasNext() { // TODO Auto-generated method stub //判断堆栈是否为空 if(stack.empty()){ return false; }else { Iterator iterator=(Iterator) stack.peek(); //判断迭代器是否遍历到最后元素 if(!iterator.hasNext()){ stack.pop(); return hasNext(); }else { return true; } } } @Override public Object next() { // TODO Auto-generated method stub if(hasNext()){ Iterator iterator=(Iterator) stack.peek(); MenuComponent menuComponent=(MenuComponent) iterator.next(); //如果是菜单的话 入栈 遍历 菜单中的菜单项 if(menuComponent instanceof Menu) { stack.push(menuComponent.createIterator()); } return menuComponent; }else { return null; } } @Override public void remove() { // TODO Auto-generated method stub throw new UnsupportedOperationException(); } }
空迭代器
package com.undergrowth.composition; import java.util.Iterator; public class NullIterator implements Iterator { @Override public boolean hasNext() { // TODO Auto-generated method stub return false; } @Override public Object next() { // TODO Auto-generated method stub return null; } @Override public void remove() { // TODO Auto-generated method stub throw new UnsupportedOperationException(); } }
服务员 操作菜单
package com.undergrowth.composition; import java.util.Iterator; public class Waitress { MenuComponent menuComponent; public Waitress(MenuComponent menuComponent) { super(); this.menuComponent = menuComponent; } public void print(){ menuComponent.print(); } /** * 打印菜单中的素菜菜单项 */ public void printVegetarianName(){ Iterator iteratorAll=menuComponent.createIterator(); while (iteratorAll.hasNext()) { MenuComponent currMenuComponent = (MenuComponent) iteratorAll.next(); try { //表示是菜单项 并且是素菜 if(currMenuComponent.isVegetarian()){ System.out.println(currMenuComponent); } } catch (Exception e) { // TODO: handle exception //菜单 会抛出异常 } } } }
测试
package com.undergrowth.composition.test; import static org.junit.Assert.*; import org.junit.Test; import com.undergrowth.composition.Menu; import com.undergrowth.composition.MenuComponent; import com.undergrowth.composition.MenuItem; import com.undergrowth.composition.Waitress; public class MenuComponentTest { @Test public void test() { //构建菜单树 MenuComponent coffeeMenuComponent=new Menu("咖啡菜单", "各种口味的咖啡"); MenuComponent dessert=new Menu("甜点菜单", "喝咖啡的时候,还可以来点甜点"); MenuComponent beverage=new Menu("饮料菜单", "品尝甜点的时候,再来点饮料"); beverage.add(new MenuItem("柠檬雪碧", 22, "加冰,口感更好", true)); dessert.add(new MenuItem("酸奶蜂蜜冰淇淋", 57, "口感新颖独特,视觉效果也是一流", true)); dessert.add(new MenuItem("小粉猪奶黄包", 37, "憨态可掬的小粉猪奶黄包", true)); dessert.add(beverage); coffeeMenuComponent.add(dessert); coffeeMenuComponent.add(new MenuItem("拿铁咖啡", 100, "咖啡与牛奶的交融", true)); coffeeMenuComponent.add(new MenuItem("越南咖啡", 200, "采用纯正的越南咖啡豆", true)); coffeeMenuComponent.add(new MenuItem("美式咖啡", 80, "清新的风味中不失本香", true)); MenuComponent chineseMenuComponent=new Menu("中国菜菜单", "美味的中国菜"); chineseMenuComponent.add(new MenuItem("宫保鸡", 45, "宫保鸡丁是川菜的代表菜,由鸡脯肉、干辣椒、花生米炒制而成,香辣好吃", false)); chineseMenuComponent.add(new MenuItem("糖醋里脊", 78, "糖醋里脊色泽红亮、酸甜可口、外酥里嫩", false)); chineseMenuComponent.add(new MenuItem("烤鸭", 80, "北京烤鸭,被誉为“天下美味”而驰名中外,它更以色泽红润,肉质细嫩,味道醇厚,肥而不腻的特色而享誉海内外", false)); MenuComponent allmenus=new Menu("根菜单", "所有菜单的入口"); allmenus.add(coffeeMenuComponent); allmenus.add(chineseMenuComponent); Waitress waitress=new Waitress(allmenus); waitress.print(); System.out.println(" "); System.out.println("==========================打印素食===================================="); waitress.printVegetarianName(); } }
控制台输出
根菜单,所有菜单的入口 =============================== 咖啡菜单,各种口味的咖啡 =============================== 甜点菜单,喝咖啡的时候,还可以来点甜点 =============================== MenuItem [name=酸奶蜂蜜冰淇淋, price=57.0, description=口感新颖独特,视觉效果也是一流, vegetarian=true] MenuItem [name=小粉猪奶黄包, price=37.0, description=憨态可掬的小粉猪奶黄包, vegetarian=true] 饮料菜单,品尝甜点的时候,再来点饮料 =============================== MenuItem [name=柠檬雪碧, price=22.0, description=加冰,口感更好, vegetarian=true] ============================================================== ============================================================== MenuItem [name=拿铁咖啡, price=100.0, description=咖啡与牛奶的交融, vegetarian=true] MenuItem [name=越南咖啡, price=200.0, description=采用纯正的越南咖啡豆, vegetarian=true] MenuItem [name=美式咖啡, price=80.0, description=清新的风味中不失本香, vegetarian=true] ============================================================== 中国菜菜单,美味的中国菜 =============================== MenuItem [name=宫保鸡, price=45.0, description=宫保鸡丁是川菜的代表菜,由鸡脯肉、干辣椒、花生米炒制而成,香辣好吃, vegetarian=false] MenuItem [name=糖醋里脊, price=78.0, description=糖醋里脊色泽红亮、酸甜可口、外酥里嫩, vegetarian=false] MenuItem [name=烤鸭, price=80.0, description=北京烤鸭,被誉为“天下美味”而驰名中外,它更以色泽红润,肉质细嫩,味道醇厚,肥而不腻的特色而享誉海内外, vegetarian=false] ============================================================== ============================================================== ==========================打印素食==================================== MenuItem [name=酸奶蜂蜜冰淇淋, price=57.0, description=口感新颖独特,视觉效果也是一流, vegetarian=true] MenuItem [name=小粉猪奶黄包, price=37.0, description=憨态可掬的小粉猪奶黄包, vegetarian=true] MenuItem [name=柠檬雪碧, price=22.0, description=加冰,口感更好, vegetarian=true] MenuItem [name=柠檬雪碧, price=22.0, description=加冰,口感更好, vegetarian=true] MenuItem [name=酸奶蜂蜜冰淇淋, price=57.0, description=口感新颖独特,视觉效果也是一流, vegetarian=true] MenuItem [name=小粉猪奶黄包, price=37.0, description=憨态可掬的小粉猪奶黄包, vegetarian=true] MenuItem [name=柠檬雪碧, price=22.0, description=加冰,口感更好, vegetarian=true] MenuItem [name=柠檬雪碧, price=22.0, description=加冰,口感更好, vegetarian=true] MenuItem [name=柠檬雪碧, price=22.0, description=加冰,口感更好, vegetarian=true] MenuItem [name=拿铁咖啡, price=100.0, description=咖啡与牛奶的交融, vegetarian=true] MenuItem [name=越南咖啡, price=200.0, description=采用纯正的越南咖啡豆, vegetarian=true] MenuItem [name=美式咖啡, price=80.0, description=清新的风味中不失本香, vegetarian=true]
其实 在打印素食菜单项的时候 会发现有些菜单项 重复打印了 这是因为采用堆栈进行处理时 会产生多级入栈与出栈 导致的 自己动手画画啊 或者调试一下 就清楚了