组合模式:
将对象组合成树形结构以表示‘部分-整体’的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。
用最经典的树和叶子节点的关系来描述整体-部分 关系最为恰当不过了:
在数据结构中,树有孩子节点,这个孩子节点可能是树,也可能是叶子节点。叶子节点不能再有孩子节点,但树可以有。从这里可以看出,树和叶子节点都可以被看成是 孩子节点。组合模式的目的是将整体和部分被一致对待,那么在这里,我们可以将叶子节点和树合并成一个组合。既然合并了,那么提供给客户代码的接口肯定是相同的。
1. Component 类,组合中的对象声明接口,在适当的情况下,声明所有类共有接口的默认行为。在这里,Component 类树枝和叶子的共有抽象类,也就是它定义了共有的方法,这些方法由子类去实现。
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); //显示该节点的树形结构
}
2. Composite 类,组合类。不过在这里主要行使的是树枝节点的功能。同时也体现了树枝 - 叶子 是 整体- 部分 关系。
既然既是组合类又是树枝类,那么必须会有管理子节点的功能,以及递归显示还是节点的功能。
import java.util.ArrayList;
import java.util.List;
public class Composite extends Component{
private List<Component> children = new ArrayList<Component>();
private String showDept = "";
public Composite(String name) {
super(name);
}
@Override
public void add(Component component) {
children.add(component);
}
@Override
public void remove(Component 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);
}
}
}
3. Leaf 类,叶子节点类。叶子节点没有子节点,其虽然继承 了Component 类,并重写了Component所有的方法,但只在自己需要的方法中添加有效代码:
public class Leaf extends Component{
String showDept ="";
public Leaf(String name) {
super(name);
// TODO Auto-generated constructor stub
}
@Override
public void add(Component component) {
// TODO Auto-generated method stub
}
@Override
public void remove(Component component) {
// TODO Auto-generated method stub
}
@Override
public void showComponent(int dept) {
// TODO Auto-generated method stub
for(int i=0;i<dept;i++){
showDept += "--";
}
System.out.println(showDept+name);
}
}
4. 编写测试代码,来验证我对组合模式理解的正确性
public class TestCompositePattern {
public static void main(String[] args){
Composite root = new Composite("树根");
Composite branch1 = new Composite("树枝一");
Composite branch2 = new Composite("树枝二");
Composite branch21 = new Composite("树枝二子树枝一");
branch1.add(new Leaf("树枝一叶子一"));
branch1.add(new Leaf("树枝一叶子二"));
branch1.add(new Leaf("树枝一叶子三"));
branch21.add(new Leaf("树枝二子树枝一叶子一"));
branch2.add(branch21);
root.add(branch1);
root.add(branch2);
root.showComponent(1);
}
}
结果输出:
--树根
----树枝一
------树枝一叶子一
------树枝一叶子二
------树枝一叶子三
----树枝二
------树枝二子树枝一
--------树枝二子树枝一叶子一
5.总结:
组合模式分为安全方式和透明方式;
透明方式:叶子节点和 树枝节点都具有相同的接口,在这里,Leaf 类也实现了add,remove 方法
好处:都提供给客户代码一样的接口
坏处:Leaf 类重写了不需要的方法,并且这写方法没有意义,并且可能会误导客户代码来调用这些无意义的方法。
安全方式:在Component 只声明公共都需要的接口,在本例中,Component 应该值声明showComponent() 方法,而将add,remove() 方法的声明和实现都应该放在Composite 类中。
好处:Leaf 没有无效代码
坏处:客户代码在调用树枝或叶子及节点的接口时,例如调用add 方法,得先判断是不是 Composite 类。