设计模式——组合模式

组合模式用于构建具有'整体/部分'层次结构的对象树,使得客户端可以一致地处理单个对象和对象组合。在菜单系统中,组合模式解决了合并不同菜单和统一遍历的问题,避免了额外的内存开销和不一致的处理方式。通过抽象组件MenuComponent,MenuItem和Menu实现了统一的增删查操作,使得菜单和菜单项可以平滑地组合和遍历。
摘要由CSDN通过智能技术生成

组合模式是什么?

组合模式允许你将对象组成树形结构来表现“整体/部分”的层次结构。组合能让客户以一致的方式处理个别对象和对象的组合。

组合模式解决什么问题?

现有菜单项和菜单,Menu通过ArrayList维护MenuItem:

class MenuItem {
    private String name;
    private Double price;

    public MenuItem(String name, Double price) {
        this.name = name;
        this.price = price;
    }

    public void print() {
        System.out.println("菜名:" + name + " 价格:" + price);
    }
}

class Menu {
    private ArrayList<MenuItem> menuItems = new ArrayList<>();
    private String name;

    public Menu(String name) {
        this.name = name;
    }

    public void add(MenuItem menuItem) {
        menuItems.add(menuItem);
    }

    public void remove(MenuItem menuItem) {
        menuItems.remove(menuItem);
    }

    public void print() {
        System.out.println("菜单名:" + name);
        for (MenuItem menuItem : menuItems) {
            menuItem.print();
        }
    }
}

现有两家店的菜单,一家卖主食,一家卖甜点:

Menu mainMenu = new Menu("mainMenu");
mainMenu.add(new MenuItem("鱼香肉丝", 15.0));
mainMenu.add(new MenuItem("西红柿炒鸡蛋", 15.0));
mainMenu.print();

Menu dessertMenu = new Menu("dessertMenu");
dessertMenu.add(new MenuItem("布丁", 10.0));
dessertMenu.add(new MenuItem("雪糕", 10.0));
dessertMenu.print();

现两家店合并,要求把甜点的菜单加入到主食菜单中,并实现统一遍历。

即mainMenu中不仅要有MenuItem还得有dessertMenu

实现1

在Menu内部维护Menu对象的ArrayList数组,创建方法addMenu()和removeMenu(),通过print()方法打印:

class Menu {
    private ArrayList<MenuItem> menuItems = new ArrayList<>();
    private String name;

    private ArrayList<Menu> innerMenus = new ArrayList<>();

    public Menu(String name) {
        this.name = name;
    }

    public void addItem(MenuItem menuItem) {
        menuItems.add(menuItem);
    }

    public void removeItem(MenuItem menuItem) {
        menuItems.remove(menuItem);
    }

    public void addMenu(Menu menu) {
        innerMenus.add(menu);
    }

    public void removeMenu(Menu menu) {
        innerMenus.remove(menu);
    }

    public void print() {
        System.out.println("菜单名:" + name);
        for (MenuItem menuItem : menuItems) {
            menuItem.print();
        }
        for (Menu menu : innerMenus) {
            menu.print();
        }
    }
}
  • problem1:需要额外的内存开销,且方法都是类似的
  • problem2:无法让Menu和MenuItem统一遍历

组合模式实现

抽象组件

MenuComponent里面方法都抛异常,让子类自行选择实现:

abstract class MenuComponent {
    public void add(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }

    public void remove(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }

    public void print() {
        throw new UnsupportedOperationException();
    }
}

组件实例

让MenuItem和Menu都继承MenuComponent,MenuItem重写print()打印菜名,Menu重写add()、remove()、print()完成对MenuComponent 的增删查:

class MenuItem extends MenuComponent {
    private String name;
    private Double price;

    public MenuItem(String name, Double price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public void print() {
        System.out.println("菜名:" + name + " 价格:" + price);
    }
}

class Menu extends MenuComponent {
    private ArrayList<MenuComponent> menuComponents = new ArrayList<>();
    private String name;

    public Menu(String name) {
        this.name = name;
    }

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

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

    @Override
    public void print() {
        System.out.println("菜单名:" + name);
        Iterator<MenuComponent> iterator = menuComponents.iterator();
        while (iterator.hasNext()) {
            MenuComponent menuComponent= iterator.next();
            menuComponent.print();
        }
    }
}

组合过程

可看到mainMenu可添加MenuItem,也可添加Menu,最后通过print()打印出所有菜单和菜单项:

MenuComponent dessertMenu = new Menu("subMenu");
dessertMenu.add(new MenuItem("布丁", 15.0));
dessertMenu.add(new MenuItem("雪糕", 10.0));

MenuComponent mainMenu = new Menu("MainMenu");
mainMenu.add(new MenuItem("鱼香肉丝", 15.0));
mainMenu.add(new MenuItem("西红柿炒鸡蛋", 15.0));
mainMenu.add(dessertMenu);
mainMenu.print();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值