12.组合模式

1.什么是组合模式?

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

2.通过具体实例理解组合模式

如果上一节的迭代器模式是优雅驱动设计的话(不了解的同学强烈推荐先了解下:迭代器模式),那么下面的需求就是业务驱动设计了。

在上一节的系统基础上,我们知道了,主要有以下几个类:

  • MenuItem类,菜品类,用来存储菜品的名称,价格,描述等信息。
  • DinerMenu类,夜晚餐厅菜单类,用来存储一个MenuItem数组以及相关操作。
  • PancakeHouseMenu类,煎饼屋菜单类,用来存储一个ArrayList数组来存储MenuItem以及相关操作。

现在,产品经理接到新需求了,现在客户希望DinerMenu以及PancakeHouseMenu等菜单类拥有添加子菜单的功能。

2.1 员工A的解决方案

员工A了解到这个需求后,自信满满,对产品说:没问题,这个就交给我来做!!

两天后,员工A拿着自己的设计图找到了技术总监,并希望得到技术总监的肯定。
在这里插入图片描述

员工A说: 老大,我的这个方案的做法是,首先将菜单类抽象的一些公共操作抽象出来构造一个Menu抽象类,然后让菜单实体类继承它,接着在MenuItem中组合Menu即可,这样就做到了在菜单中再添加子菜单的功能了。

技术总监提问: 那你是如何保证MenuItem中组合的Menu类是动态可变的呢?

员工A回答道:反射,首先,我们规约所有菜单实体类都必须实现一个boolean类型的构造函数,提供构造方式,例如:

DinerMenu类中必须含有下面构造函数

public DinerMenu(boolean son){
    menuItems = new MenuItem[MAX_ITEMS];
}

然后再Menu中添加如下方法:

public void addSonMenu(Class<?> cl) throws InstantiationException, IllegalAccessException, InvocationTargetException {
    Constructor<?>[] constructors = cl.getConstructors();
    for(Constructor<?> constructor:constructors){
        if(constructor.getParameters().length==1){
            Parameter[] parameters = constructor.getParameters();
            if(parameters[0].getType().isAssignableFrom(boolean.class)){
                sonMenu = (Menu) constructor.newInstance(true);
            }
        }
    }
}

根据反射来找到具体的目标构造函数进行构造即可。

技术总监接着问道: 这个方案可以试试,你先做出来看看吧!

一天后,员工A拿着自己的实现找到产品:
设计模式/src/main/java/CompositePattern/first/FirstTest.java · 严家豆/设计模式 - 码云 - 开源中国 (gitee.com)
并提供了演示程序:
在这里插入图片描述

2.2 组合模式重构代码

在员工A完成代码后,技术总监review时,总觉得虽然完成了需求,但是感觉抽象的不够完全。
于是,他叫来了员工A: 小A, 你听说过组合模式吗? 也许组合模式能让你的代码更简洁,我建议你用组合模式让你的代码更优雅。
员工A收到这个任务后,开始研究组合模式,并尝试做些改变。
在这里插入图片描述

员工A接收到任务后,抽象的更彻底,设计了如下做法,将菜单和菜品的动态部分抽象到一个MenuComponent里面,然后通过组合的方式让Menu包含MenuItem或Menu,将如何构建菜单完全交给了用户:

package CompositePattern.second;

/**
 * 组合模式允许你将对象组合成树形结构来表现 “整体/部分” 层次结构。
 * 组合能让客户以一致的方式处理个别对象及对象组合。
 */
public class MenuTestDrive {
    public static void main(String[] args) {
        //主菜单
        MenuComponent allMenus = new Menu("ALL MENUS","All menus combined");
        MenuComponent pancakeHouseMenu = new Menu("PANCAKE HOUSE MENU","Breakfast");
        pancakeHouseMenu.add(new MenuItem("土豆西红柿","就是土豆炒西红柿",true,4.77));
        MenuComponent dinerMenu = new Menu("DINER MENU","lunch");
        dinerMenu.add(new MenuItem("牛肉炒西红柿","西红柿炖牛肉",false,99.99));
        MenuComponent cafeMenu = new Menu("CAFE MENU","Dinner");
        MenuComponent dessertMenu = new Menu("DESSERT MENU","Dessert of course!");
        allMenus.add(pancakeHouseMenu);
        allMenus.add(dessertMenu);
        allMenus.add(dinerMenu);
        allMenus.add(cafeMenu);
        allMenus.print();
    }
}

运行如图所示:
在这里插入图片描述

完整代码路径如下:

设计模式/src/main/java/CompositePattern/second/MenuTestDrive.java · 严家豆/设计模式

下面请根据上面的例子再来理解下组合模式的精髓:组合模式允许我们将对象组合成树形结构来表现 “整体/部分” 层次结构。 组合能让客户以一致的方式处理个别对象以及对象组合。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小牧之

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值