组合模式
- 组合模式的也叫做整体-部分模式,它是一种将对象组合成树状的层次结构的模式,用来表示"整体-部分"的关系,使用户对单个对象和组合对象具有一致的访问性。
进一步阐述:
- 组合模式一般用来描述整体与部分的关系,它将对象组织到树形结构中,顶层的节点被称为根节点,根节点下面可以包含树枝节点和叶子节点,树枝节点下面又可以包含树枝节点和叶子节点。其实就是我们常说的"树型结构"。
组合模式包含四种角色:
- Component(抽象构件角色):它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。(总的抽象类或接口,定义一些通用的方法,比如新增、删除)
- Leaf(树叶构件角色):是组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件。
- Composite(树枝构件角色 / 中间构件角色):是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。
案例:实现当用户在商店购物后,显示其所选商品信息,并计算所选商品总价的功能。
UML类图:
客户端Client类:
java
/**
* 使用组合模式的客户端
*/
public class Client {
public static void main(String[] args) {
Bags bigBag = new Bags("大商品袋");
Bags mediumBag = new Bags("中商品袋");
Bags smallBag = new Bags("小商品袋");
Goods sneakers = new Goods("运动鞋", 1, 1198);
Goods snacks = new Goods("零食", 5, 5);
Goods vegetables = new Goods("蔬菜", 5, 1.5);
//中商品袋中放入运动鞋
mediumBag.add(sneakers);
//小商品袋中放入零食和蔬菜
smallBag.add(snacks);
smallBag.add(vegetables);
//把中商品袋和小商品袋一起放入大商品袋组合起来
bigBag.add(mediumBag);
bigBag.add(smallBag);
//打印所有的商品信息
bigBag.show();
double total = bigBag.calculation();
System.out.println("要支付的总价是:" + total);
}
}
商店物品Articles接口:
java
/**
* 商店物品(抽象构件)
*/
public interface Articles {
/**
* 计算方法
*/
double calculation();
/**
* 展示信息
*/
void show();
}
袋子Bags类:
java
/**
* 袋子类(树枝构件)
*/
public class Bags implements Articles {
/**
* 袋子名称
*/
private String name;
/**
* 持有商品的集合
*/
private List<Articles> bags = new ArrayList<>();
public Bags(String name) {
this.name = name;
}
/**
* 添加商品
*/
public void add(Articles articles) {
bags.add(articles);
}
/**
* 删除商品
*/
public void remove(Articles articles) {
bags.remove(articles);
}
/**
* 获取某一个商品
*/
public Articles getChild(int i) {
return bags.get(i);
}
/**
* 计算所有价格
*/
public double calculation() {
BigDecimal total = new BigDecimal("0");
for (Articles bag : bags) {
total = total.add(BigDecimal.valueOf(bag.calculation()));
}
return total.doubleValue();
}
/**
* 打印所有商品信息
*/
public void show() {
for (Articles bag : bags) {
bag.show();
}
}
}
商品Goods类:
java
/**
* 商品类(树叶构件)
*/
public class Goods implements Articles {
/**
* 商品名称
*/
private String name;
/**
* 商品数量
*/
private int quantity;
/**
* 商品单价
*/
private double unitPrice;
public Goods(String name, int quantity, double unitPrice) {
this.name = name;
this.quantity = quantity;
this.unitPrice = unitPrice;
}
@Override
public double calculation() {
return BigDecimal.valueOf(unitPrice)
.multiply(BigDecimal.valueOf(quantity)).doubleValue();
}
@Override
public void show() {
System.out.println(name + "(数量:" + quantity + ",单价:" + unitPrice + "元)");
}
}
总结:
- 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码。
- 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足"开闭原则"。
- 设计较复杂,客户端需要花更多时间理清类之间的层次关系。不容易限制容器中的构件。不容易用继承的方法来增加构件的新功能。
典型运用场景举例:
- 在需要表示一个对象整体与部分的层次结构的场合。例如:文件目录显示,多及目录呈现等。
- 要求对用户隐藏组合对象与单个对象的不同,用户可以用统一的接口使用组合结构中的所有对象的场合,比如树形结构中的二叉树。