前言 :
在 Iterator Design Pattern 我們使用了迭代模式來走訪 Menu 中的每一個 MenuItem, 雖然可行但只適用於一維的資料結構. 如果考慮更生活化的應用, 在一個總 Menu 中含有咖啡, 晚餐與點心的 Menu, 而每個 Menu 又有各自的 Menu 與 Menu Item, 也就是說這個 Menu 是類似於 Tree 的資料結構 (參考下圖), 這時你可以考慮使用 Composite Pattern.

Composite Pattern 介紹 :
考慮前面所述, 這時 Iterator 一維的資料走訪已經不敷使用, 取而代之的是我們將採用 Composite Pattern 來表示樹狀的資料結構 (參考下圖) :

而有關樹狀的結構以 node 來代表每一個在樹狀結構中的 component, 在這之前我們先來看看 Composite Pattern 的定義 :
The Composite Pattern allows you to compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
簡而言之就是透過 Composite Pattern 讓你可以將個別的 Component 組織成一個樹狀結構. 並且你在處理一個 Component 或者是一個樹狀結構的 Components 並沒有區別. 而所謂的
leaf node 就是沒有 children 的 component. 接著我們來看看 Composite Pattern 的 UML 類別圖 :
範例代碼 :
有了這些概念後, 接下來我們要來重新定義 UML 類別圖來解決樹形結構的 Menu 問題 :
相關代碼如下 :
- MenuComponent.java :
- package hf.dp.composite;
-
-
- public abstract class MenuComponent {
- public void add(MenuComponent comp){throw new UnsupportedOperationException();}
- public void remove(MenuComponent comp){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();};
- }
- MenuItem.java : (
Leaf node)
- package hf.dp.composite;
-
- public class MenuItem extends MenuComponent{
- private String name;
- private String description;
- private boolean isVeget;
- private double price;
-
- public MenuItem(String name, String des, boolean isVeget, double price)
- {
- this.name = name;
- this.description = des;
- this.isVeget = isVeget;
- this.price = price;
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public String getDescription() {
- return description;
- }
-
- @Override
- public boolean isVegetarian() {
- return isVeget;
- }
-
- @Override
- public double getPrice() {
- return price;
- }
-
- @Override
- public void print()
- {
- System.out.print("\t"+getName());
- if(isVegetarian())
- {
- System.out.print("(v)");
- }
- System.out.println(", Price="+getPrice());
- System.out.println("\t"+getDescription());
- }
- }
- Menu.java : (
Composite Node)
- package hf.dp.composite;
-
- import java.util.ArrayList;
- import java.util.Iterator;
-
- public class Menu extends MenuComponent{
- private String name;
- private String description;
- private ArrayList menuComponents;
-
- public Menu(String name, String dest)
- {
- this.name = name;
- this.description = dest;
- menuComponents = new ArrayList();
- }
- @Override
- public String getName(){return name;}
- @Override
- public String getDescription(){return description;}
- @Override
- public void add(MenuComponent comp){menuComponents.add(comp);}
- @Override
- public void remove(MenuComponent comp){menuComponents.remove(comp);}
- @Override
- public MenuComponent getChild(int i){return menuComponents.get(i);}
- @Override
- public void print()
- {
- System.out.print("\n"+getName()+", "+getDescription()+"\n");
- System.out.println("=====================================");
-
- for(MenuComponent comp:menuComponents)
- {
- comp.print();
- }
- }
- }
- MenuTestDrive.java : (
測試 Main 類)
- package hf.dp.composite;
-
- 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","Diner");
- MenuComponent dessertMenu = new Menu("DESSERT MENU","Dessert of course!");
-
- MenuComponent allMenus = new Menu("ALL MENUS","All menus combination");
- allMenus.add(pancakeHouseMenu);
- allMenus.add(dinerMenu);
- allMenus.add(cafeMenu);
-
- dinerMenu.add(new MenuItem("Pasta","Spaghetti with...", true, 3.89));
- dinerMenu.add(dessertMenu);
-
- dessertMenu.add(new MenuItem("Apple Pie", "Apple pie with a flakey crust, topped with...", true, 1.59));
-
- Waitress waitress = new Waitress(allMenus);
- waitress.printMenu();
- }
- }
執行結果如下 :
補充說明 :
*
史蒂芬心得筆記 : Composite Pattern (合成模式)
*
[OO 設計模式] Gossip@DesignPattern : Structural - Composite 模式
沒有留言:
張貼留言