组合模式属于对象的结构型模型,他将对象组织到树形结构中,用来描述整体和部分的关系。
Gof给的定义:组合模式组合成多个对象形成树形结构表示整体-部分的结构层次。组合模式将单个对象和组合对象(容器对象)的使用具有一致性
解决的问题:
针对客户端代码过多依赖于容器对象内部的复杂结构,如果容器对象内部结构发生改变,则客户端代码也需要过多的修改,从而导致代码维护性差、扩展性差等弊端。
应用场景:
当需求中体现的是部分与整体层次的结构时,以及希望用户代码忽略组合对象与单个对象的不同,统一使用组合结构中的所有对象时就应该考虑使用组合模式。
组合模式的UML类图如下
客户端(Client)
抽象构件(Component)
接口或者抽象类,为叶子构件和容器构件对象声明接口,报案了所有子类的共有行为的声明和实现,在抽象构件中定义了访问及管理它的子构建的方法:增加、删除、获取子构建、构件描述等
叶子构件(leaf)
在组合结构中表示叶子节点对象,在叶子节点中实现抽象构件中定义的行为,对于访问和管理子构建的方法通过异常的方式抛出
容器构件(Composite)
容器节点对象,可以有子节点,子节点可以是叶子节点构件也可以是容器构件,在其内部提供一个集合用于存储子节点,实现抽象构建中的定义的所有行为和管理访问子构件的方法,并通过递归的方式调用其子节点。
举例:
public abstract class Component {
abstract void printStruct(String preStr);
public void addChild(Component child){
throw new UnsupportedOperationException("对象不支持这个功能");
}
public Component getChildren(int index){
throw new UnsupportedOperationException("对象不支持这个功能");
}
public void removeChild(Component child){
throw new UnsupportedOperationException("对象不支持这个功能");
}
}
public class Leaf extends Component{
private String name;
public Leaf(String name) {
this.name = name;
}
@Override
void printStruct(String preStr) {
System.out.println(preStr + "--" + name);
}
}
public class Composite extends Component {
private List<Component> childComponent = null;//存储对象中包含的子组件对象
private String name;//组合对象的名字
public Composite(String name) {
this.name = name;
}
@Override
void printStruct(String preStr) {
//先将自己(也就是父目录输出)
System.out.println(preStr + "--" + name);
//如果包含组件则输出这些子组件对象
if (this.childComponent != null){
//向后缩进一格
preStr += " ";
//输出当前对象的子对象
for (Component component : childComponent){
component.printStruct(preStr);
}
}
}
@Override
public void addChild(Component child){
//延迟初始化
if (childComponent == null){
childComponent = new ArrayList<>();
}
childComponent.add(child);
}
}
public class Test {
public static void main(String[] args) {
Component root = new Composite("服装");
Component c1 = new Composite("男装");
Component c2 = new Composite("女装");
Component leaf1 = new Leaf("夹克");
Component leaf2 = new Leaf("衬衣");
Component leaf3 = new Leaf("裤子");
root.addChild(c1);
root.addChild(c2);
c1.addChild(leaf1);
c1.addChild(leaf2);
c2.addChild(leaf3);
root.printStruct(" ");
}
}
测试结果:
--服装
--男装
--夹克
--衬衣
--女装
--裤子
参考:《Java设计模式》于卫红编著