給予以前的迭代模式,餐廳的菜單管理系統須要有煎餅屋菜單和披薩菜單。如今但願在披薩菜單中可以加上一份餐後甜點的子菜單。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類中同時具備兩種類型的操做。由於客戶有機會對一個元素作一些不恰當或是沒有意義的操做,因此咱們失去了一些安全性。 以上即是組合模式的一些內容。