原理或定義
组合模式又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解藕。
结构
Component: 为参加组合的对象声明一个公共接口, 不管是组合还是叶结点.
Leaf: 在组合中表示叶子结点对象, 叶子结点没有子结点.
Composite: 表示参加组合的有子对象的对象, 并给出树枝购件的行为;
類圖
案例与代码
本模式采用的案例沿用上一篇文章,迭代器模式的餐厅合并的菜单问题项目。
需求变更:某一家店的菜单添加餐后甜点子菜单
餐厅菜单聚类结构现状:
结构抽象
需要用树形结构,节点是菜单或子菜单,叶子是菜单项
需要能够在各个菜单项之间游走,遍历
要能够有弹性的在菜单项之间游走
组合模式的设计方案:
类图:
迭代器组件类:
public class ComposeIterator implements Iterator {
private Stack<Iterator> stack = new Stack<Iterator>();
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() {
// TODO Auto-generated method stub
if (hasNext()) {
Iterator iterator = stack.peek();
MenuComponent mMenuComponent = (MenuComponent) iterator.next();
stack.push(mMenuComponent.getIterator());
return mMenuComponent;
}
return null;
}
@Override
public void remove() {
// TODO Auto-generated method stub
}
}
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
}
}
菜单组件接口:
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() { // TODO Auto-generated method stub System.out.println(getName() + "***" + getPrice() + "***" + getDescription()); } }
public class SubMenu extends MenuComponent { private ArrayList<MenuComponent> menuItems; public SubMenu() { menuItems = new ArrayList<MenuComponent>(); 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() { // TODO Auto-generated method stub System.out.println("****This is SubMenu****"); }; // 其他功能代码 }
餐厅类:public class CakeHouseMenu extends MenuComponent { private ArrayList<MenuComponent> menuItems; public CakeHouseMenu() { menuItems = new ArrayList<MenuComponent>(); 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() { // TODO Auto-generated method stub System.out.println("****This is CakeHouseMenu****"); }; // 其他功能代码 }
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() { // TODO Auto-generated method stub if (position < numberOfItems) { return true; } return false; } @Override public Object next() { // TODO Auto-generated method stub MenuComponent menuItem = menuItems[position]; position++; return menuItem; } @Override public void remove() { // TODO Auto-generated method stub } } @Override public void print() { // TODO Auto-generated method stub System.out.println("****This is DinerMenu****"); }; }
服务员类:public class Waitress { private ArrayList<MenuComponent> iterators = new ArrayList<MenuComponent>(); public Waitress() { } public void addComponent(MenuComponent mMenuComponent) { iterators.add(mMenuComponent); } public void printMenu() { Iterator iterator; MenuComponent menuItem; 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 void printVegetableMenu() { Iterator iterator; MenuComponent menuItem; 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(); if (menuItem.isVegetable()) { 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.printVegetableMenu();; } }
这个重点在于迭代器组件类,这个类对菜单项和子菜单项中的菜单项进行了递归逻辑处理。组合模式能让客户以一致的方式来处理个别对象以及对象组合。
也就是我们可以忽略对象组合与个体对象之间的差别
使用場景
1. 表示整体-部分的层次结构。
2.希望用户忽略组合对象与单个对象的不同,用户将统一的使用组合结构中的所有对象
優缺點
主要优点有:
1. 定义了包含基本对象和组合对象的类的层次结构。基本对象可以被组合成更复杂的组合对象,这个组合又会被组合,不断递归下去。
2.简化客户代码。客户可以一致的使用组合结构和单个对象。
3.使得更容易增加新增类型的组件。
缺点主要有:
很难限制组合中的组件。有时希望一个组合只能有某些特定组件。使用Composite时,不能依赖类型系统施加这些约束,而必须要在运行时刻进行检查。