組合模式

組合模式允許你將對象組合成樹形結構來表現(xiàn)“整體/部分”層次結構渡处。組合能讓客戶以一致的方式處理個別對象以及對象組合蚀浆。

示例—合并兩種菜單并訪問甜品菜單和素食菜單

有兩種餐廳菜單罗岖,分別用數(shù)組和ArrayList實現(xiàn)。現(xiàn)在需要合并兩種菜單膳凝,且合并后可以讓一個女招待的類去訪問控妻,不需要重復代碼就可以同時訪問兩種菜單。 將甜品菜單添加到午餐菜單中看尼,做到既可以訪問餐廳的所有的菜單也可以單獨訪問甜品菜單和素食菜單递鹉。

UML圖表示

組合模式-遍歷樹形菜單

代碼演示

組件基類

package TreeMenu;

import java.util.Iterator;

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();
    }

    public Iterator createIterator(){
        throw new UnsupportedOperationException();
    }
}

葉子菜單項

package TreeMenu;

import java.util.Iterator;

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;
    }

    @Override
    public String toString() {
        return name + ", " + price + " -- " + description;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getDescription() {
        return description;
    }

    @Override
    public boolean isVegetarian() {
        return vegetarian;
    }

    @Override
    public double getPrice() {
        return price;
    }

    @Override
    public void print() {
        System.out.print(" " + getName());
        if (isVegetarian()){
            System.out.print("(v)");
        }
        System.out.println(", " + getPrice());
        System.out.println("    --" + getDescription());
    }

    @Override
    public Iterator createIterator() {
        return new NullIterator();
    }
}

菜單

package TreeMenu;

import java.util.ArrayList;
import java.util.Iterator;

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;
    }

    @Override
    public void add(MenuComponent menuComponent){
        menuComponents.add(menuComponent);
    }

    @Override
    public void remove(MenuComponent menuComponent){
        menuComponents.remove(menuComponent);
    }

    @Override
    public MenuComponent getChild(int i) {
        return (MenuComponent)menuComponents.get(i);
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getDescription() {
        return description;
    }

    @Override
    public void print() {
        System.out.print("\n" + getName());
        System.out.println("," + getDescription());
        System.out.println("-------------------------");

        Iterator<MenuComponent> iterator = menuComponents.iterator();
        while (iterator.hasNext()){
            MenuComponent menuComponent =  iterator.next();
            menuComponent.print();
        }
    }

    @Override
    public Iterator createIterator() {
        return new CompositeIterator(menuComponents.iterator());
    }

}

組合迭代器

package TreeMenu;

import java.util.Iterator;
import java.util.Stack;

public class CompositeIterator implements Iterator {

    Stack stack = new Stack();

    public CompositeIterator(Iterator iterator){
        stack.push(iterator);
    }

    @Override
    public boolean hasNext() {
        if (stack.empty()){
            return false;
        }
        else {
            Iterator iterator = (Iterator) stack.peek();
            if (!iterator.hasNext()) {
                stack.pop();
                return hasNext();
            }
            else{
                return true;
            }
        }
    }

    @Override
    public Object next() {
        if (hasNext()){
            Iterator iterator = (Iterator) stack.peek();
            MenuComponent component = (MenuComponent) iterator.next();
            if (component instanceof Menu){
                stack.push(component.createIterator());
            }
            return component;
        }
        else{
            return null;
        }
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException();
    }
}

空迭代器

package TreeMenu;

import java.util.Iterator;

public class NullIterator implements Iterator {
    @Override
    public boolean hasNext() {
        return false;
    }

    @Override
    public Object next() {
        return null;
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException();
    }
}

服務員

package TreeMenu;

import java.util.Iterator;

public class Waitress {
    MenuComponent allMenus;

    public Waitress(MenuComponent allMenus){
        this.allMenus = allMenus;
    }

    public void printMenu(){
        allMenus.print();
    }

    public void printVegetarianMenu(){
        Iterator iterator = allMenus.createIterator();
        System.out.println("\nVEGETARIAN MENU\n-----");
        while (iterator.hasNext()){
            MenuComponent menuComponent = (MenuComponent) iterator.next();
            try {
                if(menuComponent.isVegetarian()){
                    menuComponent.print();
                }
            }
            catch (UnsupportedOperationException e) {}
        }
    }
}

測試代碼

package TreeMenu;

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 dessertMenu = new Menu("DESSERT MENU" , "Dessert of course!");

        MenuComponent allMenus = new Menu("All MENUS", "All menus combined");

        allMenus.add(pancakeHouseMenu);
        allMenus.add(dinerMenu);

        MenuItem d1 = new MenuItem("Vegetarian BLT",
                "(Fakin')Bacon with lettuce & tomato on whole wheat", true, 2.99);

        MenuItem d2 = new MenuItem("Vegetarian BLT",
                "(Fakin')Bacon with lettuce & tomato on whole wheat", true, 2.99);
        MenuItem d3 = new MenuItem("BLT","Bacon with lettuce & tomato on whole wheat", false,2.99);
        MenuItem d4 = new MenuItem("Soup of the day"
                ,"Soup of the day, with a side of potato salad", false,3.29);
        MenuItem d5 = new MenuItem("Hotdog","A hot dog, with saurkraut, relish, onions, topped with cheese",
                false,3.05);

        dinerMenu.add(d1);
        dinerMenu.add(d2);
        dinerMenu.add(d3);
        dinerMenu.add(d4);
        dinerMenu.add(d5);


        MenuItem p1 = new MenuItem("K&B's Pancake Breakfast",
                "Pancakes with scrambled eggs, and toast",
                true,2.99);
        MenuItem p2 = new MenuItem("Regular Pancake Breakfast",
                "Pancakes with fired eggs, sausage",
                false,2.99);
        MenuItem p3 = new MenuItem("Blueberry Pancakes",
                "Pancakes made with fresh blueberries",
                true,3.49);
        MenuItem p4 = new MenuItem("Waffles",
                "Waffles, with your choice of blueberries or strawberries",
                true,3.59);

        pancakeHouseMenu.add(p1);
        pancakeHouseMenu.add(p2);
        pancakeHouseMenu.add(p3);
        pancakeHouseMenu.add(p4);


        MenuItem ds1 = new MenuItem("Apple Pie",
                "Apple Pie with a flaky crust",
                true,1.59);
        MenuItem ds2 = new MenuItem("Banner Pie",
                "Banner Pie topped with vanilla ice cream",
                true,1.59);
        dessertMenu.add(ds1);
        dessertMenu.add(ds2);
        dinerMenu.add(dessertMenu);

        Waitress waitress = new Waitress(allMenus);
        waitress.printMenu();

        waitress.printVegetarianMenu();
    }
}

測試結果

All MENUS,All menus combined
-------------------------

PANCAKE HOUSE MENU,Breakfast
-------------------------
 K&B's Pancake Breakfast(v), 2.99
    --Pancakes with scrambled eggs, and toast
 Regular Pancake Breakfast, 2.99
    --Pancakes with fired eggs, sausage
 Blueberry Pancakes(v), 3.49
    --Pancakes made with fresh blueberries
 Waffles(v), 3.59
    --Waffles, with your choice of blueberries or strawberries

DINER MENU,Lunch
-------------------------
 Vegetarian BLT(v), 2.99
    --(Fakin')Bacon with lettuce & tomato on whole wheat
 Vegetarian BLT(v), 2.99
    --(Fakin')Bacon with lettuce & tomato on whole wheat
 BLT, 2.99
    --Bacon with lettuce & tomato on whole wheat
 Soup of the day, 3.29
    --Soup of the day, with a side of potato salad
 Hotdog, 3.05
    --A hot dog, with saurkraut, relish, onions, topped with cheese

DESSERT MENU,Dessert of course!
-------------------------
 Apple Pie(v), 1.59
    --Apple Pie with a flaky crust
 Banner Pie(v), 1.59
    --Banner Pie topped with vanilla ice cream

VEGETARIAN MENU
-----
 K&B's Pancake Breakfast(v), 2.99
    --Pancakes with scrambled eggs, and toast
 Blueberry Pancakes(v), 3.49
    --Pancakes made with fresh blueberries
 Waffles(v), 3.59
    --Waffles, with your choice of blueberries or strawberries
 Vegetarian BLT(v), 2.99
    --(Fakin')Bacon with lettuce & tomato on whole wheat
 Vegetarian BLT(v), 2.99
    --(Fakin')Bacon with lettuce & tomato on whole wheat
 Apple Pie(v), 1.59
    --Apple Pie with a flaky crust
 Banner Pie(v), 1.59
    --Banner Pie topped with vanilla ice cream
 Apple Pie(v), 1.59
    --Apple Pie with a flaky crust
 Banner Pie(v), 1.59
    --Banner Pie topped with vanilla ice cream
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市藏斩,隨后出現(xiàn)的幾起案子躏结,更是在濱河造成了極大的恐慌,老刑警劉巖狰域,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件媳拴,死亡現(xiàn)場離奇詭異黄橘,居然都是意外死亡,警方通過查閱死者的電腦和手機屈溉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門塞关,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人子巾,你說我怎么就攤上這事帆赢。” “怎么了线梗?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵椰于,是天一觀的道長。 經(jīng)常有香客問我仪搔,道長瘾婿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任烤咧,我火速辦了婚禮偏陪,結果婚禮上,老公的妹妹穿的比我還像新娘髓削。我一直安慰自己竹挡,他們只是感情好,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布立膛。 她就那樣靜靜地躺著揪罕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪宝泵。 梳的紋絲不亂的頭發(fā)上好啰,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機與錄音儿奶,去河邊找鬼框往。 笑死,一個胖子當著我的面吹牛闯捎,可吹牛的內容都是我干的椰弊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼瓤鼻,長吁一口氣:“原來是場噩夢啊……” “哼秉版!你這毒婦竟也來了?” 一聲冷哼從身側響起茬祷,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤清焕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秸妥,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡滚停,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了粥惧。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片键畴。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖影晓,靈堂內的尸體忽然破棺而出镰吵,到底是詐尸還是另有隱情檩禾,我是刑警寧澤挂签,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站盼产,受9級特大地震影響饵婆,放射性物質發(fā)生泄漏。R本人自食惡果不足惜戏售,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一侨核、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧灌灾,春花似錦搓译、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嘿般,卻和暖如春段标,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背炉奴。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工逼庞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瞻赶。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓赛糟,卻偏偏與公主長得像,于是被迫代替她去往敵國和親砸逊。 傳聞我的和親對象是個殘疾皇子璧南,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內容