大部分国家的军队都采用层次结构管理。每支部队包括几个师,师由旅构成,旅由团构成,团可以继续划分为排。最后,每个排由一小队实实在在的士兵组成。军事命令由最高层下达,通过每个层级传递,直到每位士兵都知道自己应该服从的命令。
组合模式是一种结构型设计模式,你可以使用它将对象组合成树状结构,并且能像使用独立对象一样使用它们。
问题
如果应用的核心模型能用树状结构表示,在应用中使用组合模式才有价值。
例如,你有两类对象:产品和盒子。一个盒子中可以包含多个产品或者几个较小的盒子。这些小盒子中同样可以包含一些产品或更小的盒子,以此类推。
假设你希望在这些类的基础上开发一个定购系统。订单中可以包含无包装的简单产品,也可以包含装满产品的盒子……以及其他盒子。此时你会如何计算每张订单的总价格呢?
订单中可能包括各种产品, 这些产品放置在盒子中, 然后又被放入一层又一层更大的盒子中。 整个结构看上去像是一棵倒过来的树。
你可以尝试直接计算:打开所有盒子,找到每件产品,然后计算总价。这在真实世界中或许可行,但在程序中,你并不能简单地使用循环语句来完成该工作。你必须事先知道所有产品和盒子的类别,所有盒子的嵌套层数以及其他繁杂的细节信息。因此,直接计算极不方便,甚至完全不可行。
解决方案
组合模式建议使用一个通用接口来与产品和盒子进行交互,并且在该接口中声明一个计算总价的方法。
那么方法该如何设计呢?对于一个产品,该方法直接返回其价格;对于一个盒子,该方法遍历盒子中的所有项目,询问每个项目的价格,然后返回该盒子的总价格。如果其中某个项目是小一号的盒子,那么当前盒子也会遍历其中的所有项目,以此类推,直到计算出所有内部组成部分的价格。你甚至可以在盒子的最终价格中增加额外费用,作为该盒子的包装费用。
组合模式以递归方式处理对象树中的所有项目
该方式的最大优点在于你无需了解构成树状结构的对象的具体类。你也无需了解对象是简单的产品还是复杂的盒子。你只需调用通用接口以相同的方式对其进行处理即可。当你调用该方法后,对象会将请求沿着树结构传递下去。
(例子原文)
public abstract class Component {
/**
* 个体和整体都具有
*/
public void operation(){
//编写业务逻辑
}
}
@SuppressWarnings("all")
public class Composite extends Component{
/**
* 构件容器
*/
private List componentArrayList = new ArrayList();
/**
* 增加一个叶子构件或树枝构件
*/
public void add(Component component){
this.componentArrayList.add(component);
}
/**
* 删除一个叶子构件或树枝构件
*/
public void remove(Component component){
this.componentArrayList.remove(component);
}
/**
* 获得分支下的所有叶子构件和树枝构件
*/
public List getChildren(){
return this.componentArrayList;
}
}
public class Leaf extends Component{
/**
* 可以覆写父类方法
*/
public void operation(){
}
}
@SuppressWarnings("all")
public class Client {
public static void main(String[] args) {
//创建一个根节点
Composite root = new Composite();
root.operation();
//创建一个树枝构件
Composite branch = new Composite();
//创建一个叶子节点
Leaf leaf = new Leaf();
//建立整体
root.add(branch);
branch.add(leaf);
}
/**
* 通过递归遍历树
*/
public static void showTree(Composite root){
for(Component c:root.getChildren()){
if(c instanceof Leaf){ //叶子节点
c.operation();
}else{ //树枝节点
showTree((Composite)c);
}
}
}
}
public abstract class Component {
/**
* 个体和整体都具有
*/
public void operation(){
//编写业务逻辑
}
/**
* 增加一个叶子构件或树枝构件
*/
public abstract void add(Component component);
/**
* 删除一个叶子构件或树枝构件
*/
public abstract void remove(Component component);
/**
* 获得分支下的所有叶子构件和树枝构件
*/
public abstract List getChildren();
}
public class Composite extends Component{
/**
* 构件容器
*/
private ArrayList componentArrayList = new ArrayList();
/**
* 增加一个叶子构件或树枝构件
*/
public void add(Component component){
this.componentArrayList.add(component);
}
/**
* 删除一个叶子构件或树枝构件
*/
public void remove(Component component){
this.componentArrayList.remove(component);
}
/**
* 获得分支下的所有叶子构件和树枝构件
*/
public List getChildren(){
return this.componentArrayList;
}
}
public class Leaf extends Component {
public void add(Component component) {
//空实现
}
public void remove(Component component) {
//空实现
}
public List getChildren() {
//空实现
return null;
}
}
@SuppressWarnings("all")
public class Client {
public static void main(String[] args) {
//创建一个根节点
Composite root = new Composite();
root.operation();
//创建一个树枝构件
Composite branch = new Composite();
//创建一个叶子节点
Leaf leaf = new Leaf();
//建立整体
root.add(branch);
branch.add(leaf);
}
/**
* 通过递归遍历树
*/
public static void showTree(Component root){
for(Component c:root.getChildren()){
if(c instanceof Leaf){ //叶子节点
c.operation();
}else{ //树枝节点
showTree(c);
}
}
}
}
某一天你的手机掉进马桶了,不能用了,这时候你的女朋友正好送你了一款最新的5G手机作为礼物。手机的包装盒一般是这样的
public abstract class Component {
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public abstract void display(int index);
}
public class Box extends Component {
private List components = new ArrayList<>();
public Box(String desc) {
this.setDesc(desc);
}
public void add(Component component) {
this.components.add(component);
}
public void remove(Component component) {
this.components.remove(component);
}
@Override
public void display(int index) {
for (int i = 0; i < index; i++) {
System.out.print("———");
}
System.out.println(this.getDesc());
this.components.forEach(c -> {
c.display(index + 1);
});
}
}
public class Gift extends Component {
public Gift(String desc) {
this.setDesc(desc);
}
@Override
public void display(int index) {
for (int i = 0; i < index; i++) {
System.out.print("———");
}
System.out.println(this.getDesc());
}
}
public class Client {
public static void main(String[] args) {
Box box1 = new Box("大盒子");
Box box2 = new Box("中盒子");
Box box3 = new Box("小盒子1");
Box box4 = new Box("小盒子2");
Gift gift1 = new Gift("手机");
Gift gift2 = new Gift("充电器");
Gift gift3 = new Gift("耳机");
/**
* 把手机和中盒子装进大盒子
* 把两个小盒子装进中盒子
* 把耳机和充电器分别装进两个小盒子
*/
box1.add(gift1);
box1.add(box2);
box2.add(box3);
box2.add(box4);
box3.add(gift2);
box4.add(gift3);
box1.display(0);
}
}
输出
大盒子
———手机
———中盒子
——————小盒子1
—————————充电器
——————小盒子2
—————————耳机
public abstract class Component {
private String desc;
private List components = new ArrayList<>();
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public List getComponents() {
return components;
}
public void setComponents(List components) {
this.components = components;
}
public abstract void add(Component component);
public abstract void remove(Component component);
public abstract void display(int index);
}
public class Box extends Component {
public Box(String desc) {
this.setDesc(desc);
}
@Override
public void add(Component component) {
this.getComponents().add(component);
}
@Override
public void remove(Component component) {
this.getComponents().remove(component);
}
@Override
public void display(int index) {
for (int i = 0; i < index; i++) {
System.out.print("———");
}
System.out.println(this.getDesc());
this.getComponents().forEach(c -> {
c.display(index + 1);
});
}
}
public class Gift extends Component {
public Gift(String desc) {
this.setDesc(desc);
}
@Override
public void add(Component component) {
// 空实现
}
@Override
public void remove(Component component) {
// 空实现
}
@Override
public void display(int index) {
for (int i = 0; i < index; i++) {
System.out.print("———");
}
System.out.println(this.getDesc());
}
}
public class Client {
public static void main(String[] args) {
Box box1 = new Box("大盒子");
Box box2 = new Box("中盒子");
Box box3 = new Box("小盒子1");
Box box4 = new Box("小盒子2");
Gift gift1 = new Gift("手机");
Gift gift2 = new Gift("充电器");
Gift gift3 = new Gift("耳机");
/**
* 把手机和中盒子装进大盒子
* 把两个小盒子装进中盒子
* 把耳机和充电器分别装进两个小盒子
*/
box1.add(gift1);
box1.add(box2);
box2.add(box3);
box2.add(box4);
box3.add(gift2);
box4.add(gift3);
box1.display(0);
}
}
输出
大盒子
———手机
———中盒子
——————小盒子1
—————————充电器
——————小盒子2
—————————耳机