给予以前的迭代模式,餐厅的菜单管理系统须要有煎饼屋菜单和披萨菜单。如今但愿在披萨菜单中可以加上一份餐后甜点的子菜单。java
在迭代模式中,披萨菜单是用数组维护的,咱们须要让披萨菜单持有一份子菜单,可是不能真的把他赋值给菜单项数组,由于类型不一样,因此不能这么作。数组
因此,须要从新实现煎饼屋菜单和披萨菜单了。事实是,咱们已经到达了一个复杂级别,若是如今不从新设计,就没法容纳将来增长的菜单或子菜单的需求。咱们须要一下改变:安全
咱们要使用组合模式来解决这个问题,但并无放弃迭代器模式,它仍然是解决方案中的一部分,然而管理菜单的问题已经到了一个迭代器没法解决的新维度。因此,咱们将倒退几步,使用组合模式来解决。this
组合模式让咱们能用树形方式建立对象的结构,树里面包含了组合以及个别的对象。使用组合结构,咱们能把相同的操做应用在组合的个别对象上,换句话说,在大多数状况下,咱们能够忽略对象组合和个别对象之间的差异。spa
咱们要如何将组合模式利用在菜单上呢?一开始,咱们须要建立一个组件接口来做为菜单和菜单项的共同接口,让咱们可以用赞成的作法来处理菜单和菜单项。来看看设计的类图:.net
菜单组件MenuComponent提供了一个接口,让菜单项和菜单共同使用。由于咱们但愿可以为这些方法提供默认的实现,因此咱们在这里能够把MenuComponent接口换成一个抽象类。在这个类中,有显示菜单信息的方法getName()等,还有操纵组件的方法add(),remove(),getChild()等。设计
菜单项MenuItem覆盖了显示菜单信息的方法,而菜单Menu覆盖了一些对他有意义的方法。code
具体来看看代码实现:component
package cn.net.bysoft.composite; public abstract class MenuComponent { // add,remove,getchild // 把组合方法组织在一块儿,即新增、删除和取得菜单组件 public void add(MenuComponent component) { throw new UnsupportedOperationException(); } public void remove(MenuComponent component) { throw new UnsupportedOperationException(); } public MenuComponent getChild(int i) { throw new UnsupportedOperationException(); } // 操做方法:他们被菜单项使用。 public String getName() { throw new UnsupportedOperationException(); } public String getDescription() { throw new UnsupportedOperationException(); } public double getPrice() { throw new UnsupportedOperationException(); } public boolean isVegetarian() { throw new UnsupportedOperationException(); } public void print() { throw new UnsupportedOperationException(); } }
package cn.net.bysoft.composite; public class MenuItem extends MenuComponent { String name; String description; boolean vegetarian; double price; public MenuItem(String name, String description, boolean vegetarian, double price) { this.name = name; this.description = description; this.vegetarian = vegetarian; this.price = price; } public String getName() { return name; } public String getDescription() { return description; } public boolean isVegetarian() { return vegetarian; } public double getPrice() { return price; } public void print() { System.out.println(" " + getName()); if (isVegetarian()) { System.out.println("(V)"); } System.out.println(", " + getPrice()); System.out.println(" -- " + getDescription()); } }
package cn.net.bysoft.composite; import java.util.ArrayList; import java.util.Iterator; public class Menu extends MenuComponent { ArrayList<MenuComponent> menuComponents = new ArrayList<MenuComponent>(); String name; String description; public Menu(String name, String description) { this.name = name; this.description = description; } public void add(MenuComponent menuComponent) { menuComponents.add(menuComponent); } public void remove(MenuComponent menuComponent) { menuComponents.remove(menuComponent); } public MenuComponent getChild(int i) { return menuComponents.get(i); } public String getName() { return name; } public String getDescription() { return description; } public void print() { System.out.println("\n" + getName()); System.out.println(", " + getDescription()); System.out.println("----------------------"); Iterator<MenuComponent> iterator = menuComponents.iterator(); while(iterator.hasNext()) { MenuComponent menuComponent = iterator.next(); menuComponent.print(); } } }
package cn.net.bysoft.composite; public class Waitress { MenuComponent allMenus; public Waitress(MenuComponent allMenus) { this.allMenus = allMenus; } public void printMenu() { allMenus.print(); } }
package cn.net.bysoft.composite; public class Client { public static void main(String[] args) { // 建立菜单对象 MenuComponent pancakeHouseMenu = new Menu("煎饼屋菜单", "提供各类煎饼。"); MenuComponent pizzaHouseMenu = new Menu("披萨屋菜单", "提供各类披萨。"); MenuComponent cafeMenu = new Menu("咖啡屋菜单", "提供各类咖啡"); // 建立一个顶层的菜单 MenuComponent allMenus = new Menu("All Menus", "All menus combined"); // 把全部菜单都添加到顶层菜单 allMenus.add(pancakeHouseMenu); allMenus.add(pizzaHouseMenu); allMenus.add(cafeMenu); // 在这里加入菜单项 pancakeHouseMenu.add(new MenuItem("苹果煎饼", "香甜苹果煎饼", true, 5.99)); pizzaHouseMenu.add(new MenuItem("至尊披萨", "意大利至尊咖啡", false, 12.89)); cafeMenu.add(new MenuItem("美式咖啡", "香浓美式咖啡", true, 3.89)); Waitress waitress = new Waitress(allMenus); waitress.printMenu(); } }
组合博士以单一责任设计原则换取透明性。经过让组件的接口同时包含一些管理子节点和叶节点的操做,客户就能够将组合和叶节点一视同仁。也就是说,一个元素到底是组合仍是叶节点,对客户是透明的。对象
如今,咱们在MenuComponent类中同时具备两种类型的操做。由于客户有机会对一个元素作一些不恰当或是没有意义的操做,因此咱们失去了一些安全性。 以上即是组合模式的一些内容。