09 组合模式(Composite Pattern)

本篇博文说的是组合模式

描述性文字

组合模式,又称为 部分整体模式,把具有相似的一组对象 当做一个对象处理,用一种树状的结构来组合对象,再提供统一的方法去访问相似的对象,以此忽略掉对象与对象容器间的差别。

举个栗子

注:此处直接使用的是原图。

假设这两类需求如下:

菜单:菜单名,描述信息,添加,添加删除子菜单或菜品 递归打印出所有的子菜单与菜品!

菜品:菜名,描述信息,价格,打印信息好的,先试试不用组合模式,要怎么写~

不使用组合模式写菜单

示例代码:

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。

UML图

使用情景

  • 如果你想表示对象的部分-整体层次结构,可以选用组合模式,把整体和部分的操作统一起来,使得层次结构实现更简单,从外 部来使用这个层次结构也简单;
  • 如果你希望统一的使用组合结构中的所有对象,可以选用组合模式,这正是组合模式提供的主要功能;

优缺点

优点:

让客户端更加简单,客户端不需要再操心面对的是组合对象还是叶节点对象,所以不需要写一大堆if语句来保证他们对正确的对象调用了正确 的方法。通常,他们只需要对整个结构调用一个方法并执行操作就可以了。

缺点:

容易增加新的组件也会带来一些问题,比如很难限制组合中的组件类型。 这在需要检测组件类型的时候,使得我们不能依靠编译期的类型约束来 完成,必须在运行期间动态检测。

猜你喜欢

转载自blog.csdn.net/Burgess_Lee/article/details/83382711
今日推荐