- 定义:
将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。 -
UML:
-
模型:
餐厅点餐软件上的,菜单->子菜单->菜单项,菜单下可能有子菜单或者菜单项,子菜单下也可能有子菜单或菜单项,类似树形结构
//抽象出统一的菜单组件(这个是统一对外暴露的数据结构)
public abstract class MenuComponent {
public String getName() {
return "";
}
public String getDescription() {
return "";
}
public float getPrice() {
return 0;
}
public boolean isVegetable() {
return false;
}
public abstract void print();
public Iterator getIterator() {
return new NullIterator();
}
}
//具体的一个菜单项
public class MenuItem extends MenuComponent{
private String name,description;
private boolean vegetable;
private float price;
public MenuItem(String name,String description,boolean vegetable,float price){
this.name=name;
this.description=description;
this.vegetable=vegetable;
this.price=price;
}
@Override
public String getName(){
return name;
}
@Override
public String getDescription(){
return description;
}
@Override
public float getPrice(){
return price;
}
@Override
public boolean isVegetable(){
return vegetable;
}
@Override
public void print() {
System.out.println(getName() + "***" + getPrice() + "***"
+ getDescription());
}
}
//菜单
public class DinerMenu extends MenuComponent {
private final static int Max_Items = 5;
private int numberOfItems = 0;
//数组方式记录子菜单项
private MenuComponent[] menuItems;
public DinerMenu() {
menuItems = new MenuComponent[Max_Items];
addItem("vegetable Blt", "bacon&lettuce&tomato&cabbage", true, 3.58f);
addItem("Blt", "bacon&lettuce&tomato", false, 3.00f);
addItem("bean soup", "bean&potato salad", true, 3.28f);
addItem("hotdog", "onions&cheese&bread", false, 3.05f);
addSubMenu(new SubMenu());
}
private void addItem(String name, String description, boolean vegetable,
float price) {
MenuItem menuItem = new MenuItem(name, description, vegetable, price);
if (numberOfItems >= Max_Items) {
System.err.println("sorry,menu is full!can not add another item");
} else {
menuItems[numberOfItems] = menuItem;
numberOfItems++;
}
}
//子菜单再添加子菜单(子菜单特有的方法)
private void addSubMenu(MenuComponent mMenuComponent){
if (numberOfItems >= Max_Items) {
System.err.println("sorry,menu is full!can not add another item");
} else {
menuItems[numberOfItems] = mMenuComponent;
numberOfItems++;
}
}
//这里返回的是一个包装迭代器,
public Iterator getIterator() {
return new ComposeIterator(new DinerIterator());
}
//自己的迭代器
class DinerIterator implements Iterator {
private int position;
public DinerIterator() {
position = 0;
}
@Override
public boolean hasNext() {
if (position < numberOfItems) {
return true;
}
return false;
}
@Override
public Object next() {
MenuComponent menuItem = menuItems[position];
position++;
return menuItem;
}
@Override
public void remove() {}
}
@Override
public void print() {
System.out.println("****This is DinerMenu****");
};
}
//装饰迭代器(操作时先调用被装饰者方法)
public class ComposeIterator implements Iterator {
private Stack stack = new Stack();
public ComposeIterator(Iterator iterator) {
stack.push(iterator);
}
@Override
public boolean hasNext() {
// TODO Auto-generated method stub
if (stack.empty()) {
return false;
}
Iterator iterator = stack.peek();
if (!iterator.hasNext()) {
stack.pop();
return hasNext();
} else {
return true;
}
}
@Override
public Object next() {
if (hasNext()) {
Iterator iterator = stack.peek();
MenuComponent mMenuComponent = (MenuComponent) iterator.next();
stack.push(mMenuComponent.getIterator());
return mMenuComponent;
}
return null;
}
@Override
public void remove() {}
}
//子菜单
public class SubMenu extends MenuComponent {
private ArrayList menuItems;
public SubMenu() {
menuItems = new ArrayList();
addItem("Apple Cookie", "Apple&candy&Cookie", true, 1.99f);
addItem("Banana Cookie", "Banana&candy&Cookie", false, 1.59f);
addItem("Orange Cookie", "Orange&Cookie", true, 1.29f);
}
private void addItem(String name, String description, boolean vegetable,
float price) {
MenuItem menuItem = new MenuItem(name, description, vegetable, price);
menuItems.add(menuItem);
}
public Iterator getIterator() {
return new ComposeIterator(menuItems.iterator());
}
@Override
public void print() {
System.out.println("****This is SubMenu****");
};
// 其他功能代码
}
//缺省适配
public class NullIterator implements Iterator{
@Override
public boolean hasNext() {
return false;
}
@Override
public Object next() {
return null;
}
@Override
public void remove() {}
}
//没有子菜单的菜单
public class CakeHouseMenu extends MenuComponent {
//集合形式存储菜单项
private ArrayList menuItems;
public CakeHouseMenu() {
menuItems = new ArrayList();
addItem("KFC Cake Breakfast", "boiled eggs&toast&cabbage", true, 3.99f);
addItem("MDL Cake Breakfast", "fried eggs&toast", false, 3.59f);
addItem("Stawberry Cake", "fresh stawberry", true, 3.29f);
addItem("Regular Cake Breakfast", "toast&sausage", true, 2.59f);
}
private void addItem(String name, String description, boolean vegetable,
float price) {
MenuItem menuItem = new MenuItem(name, description, vegetable, price);
menuItems.add(menuItem);
}
public Iterator getIterator() {
return new ComposeIterator(menuItems.iterator());
}
@Override
public void print() {
System.out.println("****This is CakeHouseMenu****");
};
// 其他功能代码
}
- 使用组合模式:
public class Waitress {
private ArrayList iterators = new ArrayList();
public Waitress() {}
public void addComponent(MenuComponent mMenuComponent) {
iterators.add(mMenuComponent);
}
public void printMenu() {
Iterator iterator;
MenuComponent menuItem;
//遍历时并不关心菜单或子菜单项的数据结构,只要调用其暴露出来的接口Iterator。
for (int i = 0, len = iterators.size(); i < len; i++) {
iterators.get(i).print();
iterator = iterators.get(i).getIterator();
while (iterator.hasNext()) {
menuItem = (MenuComponent) iterator.next();
menuItem.print();
}
}
}
}
- 测试:
public class MainTest {
public static void main(String[] args) {
Waitress mWaitress = new Waitress();
CakeHouseMenu mCakeHouseMenu = new CakeHouseMenu();
DinerMenu mDinerMenu = new DinerMenu();
mWaitress.addComponent(mCakeHouseMenu);
mWaitress.addComponent(mDinerMenu);
mWaitress.printMenu();
}
}
- 通过使用组合模式,我们将菜单与子菜单抽象成菜单组件。对使用者来说是透明的,操作具有一致性,忽略整体与部分的差异。
子菜单可以看成存储菜单组件的容器,这样我们就可以组合出很多层次,形成复杂的树形结构。