/**
*
*
* 组合模式: 可以使组合对象形成树形结构,以表现出整体/部分的结构,并提供一致的方法访问整体和局部
* 组合结构内任意对象称为组件,组件可以是组合,也可以是叶节点
* 客户可以将对象的集合以及个别的对象一视同仁
*
* 运用了递归迭代的思想
*
* 外部迭代器必须维护它在遍历中的位置,以便外部客户可以通过调用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("\n\n\n");
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]
其实 在打印素食菜单项的时候 会发现有些菜单项 重复打印了 这是因为采用堆栈进行处理时 会产生多级入栈与出栈 导致的 自己动手画画啊 或者调试一下 就清楚了