设计模式之组合模式浅析

     
/**
 * 
 * 
 * 组合模式: 可以使组合对象形成树形结构,以表现出整体/部分的结构,并提供一致的方法访问整体和局部
 *   组合结构内任意对象称为组件,组件可以是组合,也可以是叶节点
 * 客户可以将对象的集合以及个别的对象一视同仁
 * 
 * 运用了递归迭代的思想
 * 
 * 外部迭代器必须维护它在遍历中的位置,以便外部客户可以通过调用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]




  其实   在打印素食菜单项的时候  会发现有些菜单项 重复打印了 这是因为采用堆栈进行处理时  会产生多级入栈与出栈 导致的 自己动手画画啊  或者调试一下 就清楚了

posted on 2014-12-17 20:29  liangxinzhi  阅读(132)  评论(0编辑  收藏  举报