本篇博文说的是组合模式
组合模式,又称为 部分整体模式,把具有相似的一组对象 当做一个对象处理,用一种树状的结构来组合对象,再提供统一的方法去访问相似的对象,以此忽略掉对象与对象容器间的差别。
注:此处直接使用的是原图。
假设这两类需求如下:
菜单:菜单名,描述信息,添加,添加删除子菜单或菜品 递归打印出所有的子菜单与菜品!
菜品:菜名,描述信息,价格,打印信息好的,先试试不用组合模式,要怎么写~
示例代码:
package structPattrn.compositePattern; import java.util.ArrayList; import java.util.List; /** * 组合模式测试例程 * @Package structPattrn.compositePattern * @Title: CompositePatternDemo.java * @Company: $ * @author BurgessLee * @date 2018年10月25日-下午5:06:05 * @Description: $ */ public class CompositePatternDemo { public static void main(String[] args) { //不用组合模式测试例程 Menu menu = new Menu("大菜单","包含所有的子菜单"); Menu drinkMenu = new Menu("饮品菜单","都是喝的"); Menu eatMenu = new Menu("小吃菜单","都是吃的"); MilkTea milkTea = new MilkTea("珍珠卖茶","珍珠+奶茶", 5); Juice juice = new Juice("猕猴桃饮料","无添加剂",5); HandCake handCake = new HandCake("咖喱鱼蛋","微辣",6); FishBoll fishBoll = new FishBoll("培根手抓饼","正宗台湾风味",6); drinkMenu.addMilkTea(milkTea); drinkMenu.addJuice(juice); eatMenu.addHandCake(handCake); eatMenu.addFishBoll(fishBoll); menu.addMenu(drinkMenu); menu.addMenu(eatMenu); System.out.println(menu.toString()); } } //以下部分代码使用的不是组合模式实现的========================================================================== class MilkTea{ private String name; private String desc; private int price; public MilkTea(String name, String desc, int price) { super(); this.name = name; this.desc = desc; this.price = price; } @Override public String toString() { return "MilkTea [name=" + name + ", desc=" + desc + ", price=" + price + "]"; } } class Juice{ private String name; private String desc; private int price; public Juice(String name, String desc, int price) { super(); this.name = name; this.desc = desc; this.price = price; } @Override public String toString() { return "Juice [name=" + name + ", desc=" + desc + ", price=" + price + "]"; } } class HandCake{ private String name; private String desc; private int price; public HandCake(String name, String desc, int price) { super(); this.name = name; this.desc = desc; this.price = price; } @Override public String toString() { return "HandCake [name=" + name + ", desc=" + desc + ", price=" + price + "]"; } } class FishBoll{ private String name; private String desc; private int price; public FishBoll(String name, String desc, int price) { super(); this.name = name; this.desc = desc; this.price = price; } @Override public String toString() { return "FishBoll [name=" + name + ", price=" + price + "]"; } } class Menu{ private String name; private String desc; private List<Menu> menus = new ArrayList<>(); private List<MilkTea> milkTeas = new ArrayList<>(); private List<Juice> juices = new ArrayList<>(); private List<HandCake> handCakes = new ArrayList<>(); private List<FishBoll> fishBolls = new ArrayList<>(); public Menu(String name, String desc) { super(); this.name = name; this.desc = desc; } public void addMilkTea(MilkTea milkTea){ this.milkTeas.add(milkTea); } public void addJuice(Juice juice){ this.juices.add(juice); } public void addHandCake(HandCake handCake){ this.handCakes.add(handCake); } public void addFishBoll(FishBoll fishBoll){ this.fishBolls.add(fishBoll); } public void addMenu(Menu menu){ this.menus.add(menu); } @Override public String toString() { return "Menu [name=" + name + ", desc=" + desc + ", menus=" + menus + ", milkTeas=" + milkTeas + ", juices=" + juices + ", handCakes=" + handCakes + ", fishBolls=" + fishBolls + "]"; } }打印结果:
Menu [name=大菜单, desc=包含所有的子菜单, menus=[Menu [name=饮品菜单, desc=都是喝的, menus=[], milkTeas=[MilkTea [name=珍珠卖茶, desc=珍珠+奶茶, price=5]], juices=[Juice [name=猕猴桃饮料, desc=无添加剂, price=5]], handCakes=[], fishBolls=[]], Menu [name=小吃菜单, desc=都是吃的, menus=[], milkTeas=[], juices=[], handCakes=[HandCake [name=咖喱鱼蛋, desc=微辣, price=6]], fishBolls=[FishBoll [name=培根手抓饼, price=6]]]], milkTeas=[], juices=[], handCakes=[], fishBolls=[]]示例代码:
abstract class AbstractMenu{ public abstract void add(AbstractMenu menu); public abstract AbstractMenu get(int index); public abstract String getString(); } class MileTeaNew extends AbstractMenu{ private String name; private String desc; private int price; public MileTeaNew(String name, String desc, int i) { super(); this.name = name; this.desc = desc; this.price = i; } @Override public void add(AbstractMenu menu) { /*未使用*/ } @Override public AbstractMenu get(int index) { return null; } @Override public String getString() { return toString(); } @Override public String toString() { return "MileTeaNew [name=" + name + ", desc=" + desc + ", price=" + price + "]"; } } class JuiceNew extends AbstractMenu{ private String name; private String desc; private int price; public JuiceNew(String name, String desc) { super(); this.name = name; this.desc = desc; } @Override public void add(AbstractMenu menu) { /*未使用*/ } @Override public AbstractMenu get(int index) { return null; } @Override public String getString() { return toString(); } @Override public String toString() { return "MileTeaNew [name=" + name + ", desc=" + desc + ", price=" + price + "]"; } } class HandCakeNew extends AbstractMenu{ private String name; private String desc; private int price; public HandCakeNew(String name, String desc) { super(); this.name = name; this.desc = desc; } @Override public void add(AbstractMenu menu) { /*未使用*/ } @Override public AbstractMenu get(int index) { return null; } @Override public String getString() { return toString(); } @Override public String toString() { return "MileTeaNew [name=" + name + ", desc=" + desc + ", price=" + price + "]"; } } class FishBollNew extends AbstractMenu{ private String name; private String desc; private int price; public FishBollNew(String name, String desc) { super(); this.name = name; this.desc = desc; } @Override public void add(AbstractMenu menu) { /*未使用*/ } @Override public AbstractMenu get(int index) { return null; } @Override public String getString() { return toString(); } @Override public String toString() { return "MileTeaNew [name=" + name + ", desc=" + desc + ", price=" + price + "]"; } } class MenuNew extends AbstractMenu{ private String name; private String desc; private List<AbstractMenu> menus = new ArrayList<>(); public MenuNew(String name, String desc) { super(); this.name = name; this.desc = desc; } @Override public void add(AbstractMenu menu) { this.menus.add(menu); } @Override public AbstractMenu get(int index) { return this.menus.get(index); } @Override public String getString() { return toString(); } @Override public String toString() { return "MenuNew [name=" + name + ", desc=" + desc + ", menus=" + menus + "]"; } }测试例程:
MenuNew menuNew = new MenuNew("大菜单","包含所有的子菜单"); MenuNew drinkMenuNew = new MenuNew("饮品菜单","都是喝的"); MenuNew eatMenuNew = new MenuNew("小吃菜单","都是吃的"); MileTeaNew milkTeaNew = new MileTeaNew("珍珠卖茶","珍珠+奶茶",6); JuiceNew juiceNew = new JuiceNew("猕猴桃饮料","无添加剂"); HandCakeNew handCakeNew = new HandCakeNew("咖喱鱼蛋","微辣"); FishBollNew fishBollNew = new FishBollNew("培根手抓饼","正宗台湾风味"); drinkMenuNew.add(milkTeaNew); drinkMenuNew.add(juiceNew); eatMenuNew.add(handCakeNew); eatMenuNew.add(fishBollNew); menuNew.add(drinkMenuNew); menuNew.add(eatMenuNew); menuNew.getString();使用了合并模式,如果此时我们要新增一个菜品,只需继承抽象构建类, 无需改动其他类,显得更加方便。
三个角色 上面也说了合并模式是用一种树状的结构来组合对象,三个名词 根节点,枝结点,叶子结点,类比上面那个菜单的图, 根节点是菜单,枝结点是饮料菜单和小吃菜单, 叶子结点是奶茶,果汁,手抓饼和鱼蛋!
Component:抽象组件,为组合中的对象声明接口,让客户端 可以通过这个接口来访问和管理整个对象结构,可以在里面为定义的 功能提供缺省的实现,比如上面的AbstractMenu类。Composite:容器组件,继承抽象组件,实现抽象组件中与 叶子组件相关的操作,比如上面的Menu类重写了get,set方法。此处重写的是toString方法也就是,抽象类中的getString方法Leaf:叶子组件,定义和实现叶子对象的行为,不再包含其它 的子节点对象,比如上面的MilkTea,Juice,HandCakeFishBall。
让客户端更加简单,客户端不需要再操心面对的是组合对象还是叶节点对象,所以不需要写一大堆if语句来保证他们对正确的对象调用了正确 的方法。通常,他们只需要对整个结构调用一个方法并执行操作就可以了。
容易增加新的组件也会带来一些问题,比如很难限制组合中的组件类型。 这在需要检测组件类型的时候,使得我们不能依靠编译期的类型约束来 完成,必须在运行期间动态检测。