--- tags: Structural Patterns --- # 合成模式 Composite ![](https://i.imgur.com/12x56i9.png) 白話文一點就是將所有的物件都視為同一種東西 讓物件可以是集合也可以是個體 ex: ![](https://i.imgur.com/6MsiPuj.png) 用這個圖做解釋 coach: 是輔導就業,提供工作上協助的人 engineer: 一般工程師 designer: 一般設計師 coach, engineer, designer都是由一個abstract class "employee" 延伸而成 component: employee 所有員工(coach, engineer, designer)的template * 描述在 Composite 中物件的interface * 實作一些共通的部分 * 定義存取、管理其 Child 物件的介面 composite: coach 在被教的同時也能夠去教別人(能有child物件) * 定義有 Child 物件的行為 * 儲存 Child 元件 * 實作 Child 相關的物件行為 leaf: engineer, designer 沒有child物件,實現單一功能 **架構能夠畫成樹狀圖** > [name=Benson] ## 架構圖 ![](https://i.imgur.com/doY7x3b.png) ## 角色 **Component: like the Glyph** * 宣告複合體內含物件之介面。 * 對Leaf、Composite一視同仁 **Leaf** * 複合結構之終端物件(不會有子節點)。 * 定義基本物件的行為。 **Composite: like the Row, Column** * 定義含子結構的節點之行為。 * 儲存子節點。 * 實作出Componet之中與子結構有關的介面。 **Client 參與者** * 利用 Composite Pattern 的人,例如 Main 類別。 ## 構思 Leaf、Componsite繼承Component 呈現「部份(part) / 整體(whole)」的關係 represent part-whole 管理子節點的部分可以使用Iterator Pattern(新增、刪除) ## 安全性(Safety)和通透性(Transparency)的取捨 把增加或刪除等操作放在不同位置。 1. 若定義在Component:通透性較好,安全性較差。無法避免別人寫出「可增、刪Leaf子節點」的程式。**要設定丟出例外防止錯誤,Leaf還是可以使用add但是會丟出例外。** 3. 若定義在Composite:安全性較好,但通透性較差。因為Leaf和Composite的介面不同。**在add時需要轉成Composite的型態。** ![](https://i.imgur.com/zjPt0dI.png) ![](https://i.imgur.com/fDkDA8J.png) ## 菜單與菜單內容的範例 ``` java //Component public abstract class 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 String getDescription() { throw new UnsupportedOperationException(); } public double getPrice() { throw new UnsupportedOperationException(); } public boolean isVegetarian() { throw new UnsupportedOperationException(); } public void print() { throw new UnsupportedOperationException(); } } //componsite public class Menu extends MenuComponent { ArrayList menuComponents = new ArrayList(); 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 (MenuComponent)menuComponents.get(i); } public String getName() { return name; } public String getDescription() { return description; } public void print() { System.out.print("\n" + getName()); System.out.println(", " + getDescription()); System.out.println("---------------------"); Iterator iterator = menuComponents.iterator(); while (iterator.hasNext()) { MenuComponent menuComponent = (MenuComponent)iterator.next(); menuComponent.print(); } } } //leaf 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 double getPrice() { return price; } public boolean isVegetarian() { return vegetarian; } public void print() { System.out.print(" " + getName()); if (isVegetarian()) { System.out.print("(v)"); } System.out.println(", " + getPrice()); System.out.println(" -- " + getDescription()); } } public class Waitress { MenuComponent allMenus; public Waitress(MenuComponent allMenus) { this.allMenus = allMenus; } public void printMenu() { allMenus.print(); } } //Client public class MenuTestDrive { public static void main(String args[]) { MenuComponent pancakeHouseMenu = new Menu("PANCAKE HOUSE MENU", "Breakfast"); MenuComponent dinerMenu = new Menu("DINER MENU", "Lunch"); MenuComponent cafeMenu = new Menu("CAFE MENU", "Dinner"); MenuComponent dessertMenu = new Menu("DESSERT MENU", "Dessert of course!"); MenuComponent coffeeMenu = new Menu("COFFEE MENU", "Stuff to go with your afternoon coffee"); MenuComponent allMenus = new Menu("ALL MENUS", "All menus combined"); allMenus.add(pancakeHouseMenu); allMenus.add(dinerMenu); allMenus.add(cafeMenu); pancakeHouseMenu.add(new MenuItem( "K&B's Pancake Breakfast", "Pancakes with scrambled eggs, and toast", true, 2.99)); pancakeHouseMenu.add(new MenuItem( "Regular Pancake Breakfast", "Pancakes with fried eggs, sausage", false, 2.99)); pancakeHouseMenu.add(new MenuItem( "Blueberry Pancakes", "Pancakes made with fresh blueberries, and blueberry syrup", true, 3.49)); pancakeHouseMenu.add(new MenuItem( "Waffles", "Waffles, with your choice of blueberries or strawberries", true, 3.59)); dinerMenu.add(new MenuItem( "Vegetarian BLT", "(Fakin') Bacon with lettuce & tomato on whole wheat", true, 2.99)); dinerMenu.add(new MenuItem( "BLT", "Bacon with lettuce & tomato on whole wheat", false, 2.99)); dinerMenu.add(new MenuItem( "Soup of the day", "A bowl of the soup of the day, with a side of potato salad", false, 3.29)); dinerMenu.add(new MenuItem( "Hotdog", "A hot dog, with saurkraut, relish, onions, topped with cheese", false, 3.05)); dinerMenu.add(new MenuItem( "Steamed Veggies and Brown Rice", "Steamed vegetables over brown rice", true, 3.99)); dinerMenu.add(new MenuItem( "Pasta", "Spaghetti with Marinara Sauce, and a slice of sourdough bread", true, 3.89)); dinerMenu.add(dessertMenu); dessertMenu.add(new MenuItem( "Apple Pie", "Apple pie with a flakey crust, topped with vanilla icecream", true, 1.59)); dessertMenu.add(new MenuItem( "Cheesecake", "Creamy New York cheesecake, with a chocolate graham crust", true, 1.99)); dessertMenu.add(new MenuItem( "Sorbet", "A scoop of raspberry and a scoop of lime", true, 1.89)); cafeMenu.add(new MenuItem( "Veggie Burger and Air Fries", "Veggie burger on a whole wheat bun, lettuce, tomato, and fries", true, 3.99)); cafeMenu.add(new MenuItem( "Soup of the day", "A cup of the soup of the day, with a side salad", false, 3.69)); cafeMenu.add(new MenuItem( "Burrito", "A large burrito, with whole pinto beans, salsa, guacamole", true, 4.29)); cafeMenu.add(coffeeMenu); coffeeMenu.add(new MenuItem( "Coffee Cake", "Crumbly cake topped with cinnamon and walnuts", true, 1.59)); coffeeMenu.add(new MenuItem( "Bagel", "Flavors include sesame, poppyseed, cinnamon raisin, pumpkin", false, 0.69)); coffeeMenu.add(new MenuItem( "Biscotti", "Three almond or hazelnut biscotti cookies", true, 0.89)); Waitress waitress = new Waitress(allMenus); waitress.printMenu(); } } Java Result: ``` >[name=閔致]