1 概述
定义:将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象使用具有一致性。
通用类图如下:
component 定义参与组合对象共有的方法和属性,可以定义一些默认行为或属性。
leaf 叶子对象,下面没有分支,遍历中最小单位。
composite 树枝对象,作用是组合树枝节点和叶子节点形成一个树的结构。
2 代码案例
英雄联盟中每件装备的合成图,有是树的结构,不过会有相同的小件(基础装备),我们把它看成是不同对象就可以使用组合模式来描述。
首先创建所有装备的抽象类,定义一些公共的方法
/**
* @author chiangtaol
* @date 2020-12-07
* @describe 装备抽象类
*/
@Getter
@Setter
public abstract class EquipmentAbstract {
/**
* 名称
*/
private String name;
/**
* 属性值
*/
private int attribute;
/**
* 父节点
*/
private EquipmentAbstract parent;
/**
* 构造方法
*/
public EquipmentAbstract(String name, int attribute) {
this.name = name;
this.attribute = attribute;
}
/**
* 获取销售价格
*/
public abstract double getSellingPrice();
/**
* 打印装备详情
*/
public String getInfo() {
StringBuffer sb = new StringBuffer();
sb.append("名称:").append(this.getName()).append(",")
.append("属性:").append(this.getAttribute()).append(",")
.append("购买价格:").append(this.getSellingPrice());
return sb.toString();
}
}
创建合成装备,和基础装备
/**
* @author chiangtaol
* @date 2020-12-07
* @describe 合成装备, 非基础装备
*/
public class CompoundEquipment extends EquipmentAbstract{
/** 合成价格*/
private double compoundPrice;
/** 由那些装备合成*/
private ArrayList<EquipmentAbstract> list = new ArrayList<>();
public ArrayList<EquipmentAbstract> getList() {
return list;
}
public void addList(EquipmentAbstract equipment) {
equipment.setParent(this);
this.list.add(equipment);
}
public double getCompoundPrice() {
return compoundPrice;
}
public void setCompoundPrice(double compoundPrice) {
this.compoundPrice = compoundPrice;
}
/**
* 构造方法
*
* @param name
* @param attribute
*/
public CompoundEquipment(String name, int attribute) {
super(name, attribute);
}
/**
* 获取销售价格
*/
@Override
public double getSellingPrice() {
double price = compoundPrice;
for (EquipmentAbstract equipment : list){
price = price + equipment.getSellingPrice();
}
return price;
}
/**
* 打印装备详情
*/
@Override
public String getInfo() {
return super.getInfo()+",其中合成价格"+compoundPrice;
}
}
/**
* @author chiangtaol
* @date 2020-12-07
* @describe 基础装备
*/
public class BaseEquipment extends EquipmentAbstract {
/**
* 商品售价
*/
private double sellingPrice;
/**
* 构造方法
*
* @param name 名称
* @param attribute 属性值
*/
public BaseEquipment(String name, int attribute) {
super(name, attribute);
}
/**
* 获取销售价格
*/
@Override
public double getSellingPrice() {
return this.sellingPrice;
}
/**
* 设置销售价格
*/
public void setSellingPrice(double sellingPrice) {
this.sellingPrice = sellingPrice;
}
}
测试代码:
@Test
public void test(){
CompoundEquipment equipment = build();
System.out.println(equipment.getInfo());
System.out.println(getInfo(equipment));
}
public String getInfo(CompoundEquipment equipment) {
String info = "";
ArrayList<EquipmentAbstract> list = equipment.getList();
for (EquipmentAbstract ea : list){
if (ea instanceof BaseEquipment){
info = info + ea.getInfo() +"\n";
}else {
info = info + ea.getInfo() +"\n" + getInfo((CompoundEquipment) ea);
}
}
return info;
}
public CompoundEquipment build(){
//小件
BaseEquipment lsj = new BaseEquipment("蓝水晶",5);
lsj.setSellingPrice(350d);
CompoundEquipment yg = new CompoundEquipment("耀光",99);
yg.setCompoundPrice(350);
yg.addList(lsj);
BaseEquipment cj = new BaseEquipment("长剑",5);
cj.setSellingPrice(350d);
BaseEquipment hsj = new BaseEquipment("红水晶",5);
hsj.setSellingPrice(350d);
CompoundEquipment js = new CompoundEquipment("净蚀",95);
js.setCompoundPrice(350);
js.addList(cj);
js.addList(hsj);
CompoundEquipment fc = new CompoundEquipment("蜂刺",94);
fc.setCompoundPrice(350);
BaseEquipment dj1 = new BaseEquipment("短剑",5);
dj1.setSellingPrice(300d);
BaseEquipment dj2 = new BaseEquipment("短剑",5);
dj2.setSellingPrice(300d);
fc.addList(dj1);
fc.addList(dj2);
//大件
CompoundEquipment sanxiangzhili = new CompoundEquipment("三项之力",999);
sanxiangzhili.setCompoundPrice(300d);
sanxiangzhili.addList(js);
sanxiangzhili.addList(fc);
sanxiangzhili.addList(yg);
return sanxiangzhili;
}
运行结果如下:
名称:三项之力,属性:999,购买价格:3000.0,其中合成价格300.0
名称:净蚀,属性:95,购买价格:1050.0,其中合成价格350.0
名称:长剑,属性:5,购买价格:350.0
名称:红水晶,属性:5,购买价格:350.0
名称:蜂刺,属性:94,购买价格:950.0,其中合成价格350.0
名称:短剑,属性:5,购买价格:300.0
名称:短剑,属性:5,购买价格:300.0
名称:耀光,属性:99,购买价格:700.0,其中合成价格350.0
名称:蓝水晶,属性:5,购买价格:350.0
3 优缺点
3.1 优点
高层模块调用简单
节点自由增加
3.2 缺点
使用场景类,直接使用了实现类,与依赖倒置原则冲突
4 使用场景
一般用于整体-部分关系的场景,如:菜单,文件、文件夹管理