组合模式定义:将对象组合成树形结构以表示“部分-整体"的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。可以用树形结构中的树枝节点和叶子节点的概念来类比。
在数据结构中,树有孩子节点,这个孩子节点可能是树枝节点,也可能是叶子节点。叶子节点不能再有孩子节点,而树枝节点还可以有。
组合模式的目的是将整体和部分一致对待,那么在这里,我们可以将叶子节点和树枝节点合并成一个组合,二者提供给客户代码的接口是一致的。
下面实现了一个组合模式的Demo。
Component类,组合中的对象生命接口,在适当情况下,声明所有类共有接口的默认行为。在这,Component定义了共有的方法,这些方法由子类去实现。
package test;
/**
* Component抽象类,Composite类和Leaf类继承此抽象类
*
* @author CYL
*
*/
public abstract class Component {
protected String name;
public Component(String name) {
this.name = name;
}
public abstract void add(Component component);
public abstract void remove(Component component);
public abstract void showComponent(int dept);
}
Composite类,组合类,体现了树枝节点的功能。
package test;
import java.util.ArrayList;
import java.util.List;
/**
* 树枝节点,可以再包含叶子节点
*
* @author CYL
*
*/
public class Composite extends Component {
private List<Component> children = new ArrayList<Component>();
private String showDept = "";
public Composite(String name) {
super(name);
}
// 复写Component中的add方法,向树枝节点中添加子节点
@Override
public void add(Component component) {
if (children.contains(component)) {
return;
} else {
children.add(component);
}
}
// 复写Component中的remove方法,删除一个子节点
@Override
public void remove(Component component) {
if (children.contains(component)) {
children.remove(component);
}
}
// 打印输出
@Override
public void showComponent(int dept) {
for (int i = 0; i < dept; i++) {
showDept += "--";
}
System.out.println(showDept + name);
for (Component component : children) {
component.showComponent(dept + 1);// dept + 1 每次for循环dept自加1
}
}
}
Leaf类,叶子节点类。 叶子节点没有子节点,其虽然继承 了Component 类,并重写了Component所有的方法,但只在自己需要的方法中添加有效代码:
package test;
/**
* 叶子节点,这里可以看到透明模式的一个缺陷:Leaf 类重写了不需要的方法,并且这写方法没有意义,并且可能会误导客户代码来调用这些无意义的方法。
*
* @author CYL
*
*/
public class Leaf extends Component {
String showDept = "";
public Leaf(String name) {
super(name);
}
@Override
public void add(Component component) {
}
@Override
public void remove(Component component) {
}
@Override
public void showComponent(int dept) {
for (int i = 0; i < dept; i++) {
showDept += "++";
}
System.out.println(showDept + name);
}
}
测试代码
package test;
public class TestCompositePattern {
public static void main(String[] args) {
// 添加树枝节点
Composite root = new Composite("树根");
Composite branch1 = new Composite("树枝1");
Composite branch2 = new Composite("树枝2");
Composite branch21 = new Composite("树枝2子树枝1");
// 为树枝节点添加叶子节点
branch1.add(new Leaf("树枝1叶子1"));
branch1.add(new Leaf("树枝1叶子2"));
branch1.add(new Leaf("树枝1叶子3"));
branch21.add(new Leaf("树枝2子树枝1叶子1"));
branch2.add(branch21);
// 将叶子节点添加到树枝节点中
root.add(branch1);
root.add(branch2);
root.showComponent(1);
}
}
结果输出:
--树根
----树枝1
++++++树枝1叶子1
++++++树枝1叶子2
++++++树枝1叶子3
----树枝2
------树枝2子树枝1
++++++++树枝2子树枝1叶子1
组合模式分为安全方式和透明方式;
透明方式:叶子节点和 树枝节点都具有相同的接口,在这里,Leaf 类也实现了add,remove 方法
好处:都提供给客户代码一样的接口
坏处:Leaf 类重写了不需要的方法,并且这写方法没有意义,并且可能会误导客户代码来调用这些无意义的方法。
安全方式:在Component 只声明公共都需要的接口,在本例中,Component 应该值声明showComponent() 方法,而将add,remove() 方法的声明和实现都应该放在Composite 类中。
好处:Leaf 没有无效代码
坏处:客户代码在调用树枝或叶子及节点的接口时,例如调用add 方法,得先判断是不是 Composite 类。