意图
将对象组合成树型结构以表示“部分-整体”的层次结构。Composite使得或用户对单个对象和组合对象的使用具有一致性。
结构图:
组合模式实现的最关键的地方是——简单对象和复合对象必须实现相同的接口。这就是组合模式能够将组合对象和简单对象进行一致处理的原因。
- Component(组合部件):抽象角色,为要组合的对象提供统一的接口;
- Leaf(叶子):在组合中表示叶结点对象,叶结点没有子结点;在组合中定义图元对象的行为。
- Composite(树枝):定义有子组件的那些组件的行为;存储子组件;在Component接口中实现与子组件有关的操作。
- Client:通过Component接口操纵组合组件的对象。
有透明式组合模式,安全式组合模式
透明式:在Component中声明所有来管理子对象的方法,其中包括Add,Remove等。这样实现Component接口的所有子类都具备了Add和Remove方法。这样做的好处是叶结点和枝结点对于外界没有区别,它们具备完全一致的接口。但其缺点是:叶子构件本来没有 Add()、Remove() 及 GetChild() 方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。
package composite;
import java.util.ArrayList;
public class CompositePattern
{
public static void main(String[] args)
{
Component c0=new Composite();
Component c1=new Composite();
Component leaf1=new Leaf("1");
Component leaf2=new Leaf("2");
Component leaf3=new Leaf("3");
c0.add(leaf1);
c0.add(c1);
c1.add(leaf2);
c1.add(leaf3);
c0.operation();
}
}
//抽象构件
interface Component
{
public void add(Component c);
public void remove(Component c);
public Component getChild(int i);
public void operation();
}
//树叶构件
class Leaf implements Component
{
private String name;
public Leaf(String name)
{
this.name=name;
}
public void add(Component c){ }
public void remove(Component c){ }
public Component getChild(int i)
{
return null;
}
public void operation()
{
System.out.println("树叶"+name+":被访问!");
}
}
//树枝构件
class Composite implements Component
{
private ArrayList<Component> children=new ArrayList<Component>();
public void add(Component c)
{
children.add(c);
}
public void remove(Component c)
{
children.remove(c);
}
public Component getChild(int i)
{
return children.get(i);
}
public void operation()
{
for(Object obj:children)
{
((Component)obj).operation();
}
}
}
树叶1:被访问!
树叶2:被访问!
树叶3:被访问!
安全式:只在Component声明共有的方法,leaf和composite实现各自的方法,这样做就不会出现上面的问题,不过由于不够透明,所有树叶和树枝类将不具有相同的接口,客户端调用需要做相应的判断,带来不方便。
组合模式使用场景
- 想表示一个对象整体或部分的层次结构。
- 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
优缺点
优点:
- 组合模式使得客户端代码可以一致地处理对象和对象容器,无需关系处理的单个对象,还是组合的对象容器。
- 将”客户代码与复杂的对象容器结构“解耦。
- 可以更容易地往组合对象中加入新的构件。
缺点:使得设计更加复杂。客户端需要花更多时间理清类之间的层次关系。(这个是几乎所有设计模式所面临的问题)。
总结
Composite模式采用树形结构来实现普遍存在的对象容器,从而将“一对多”的关系转为“一对一”,使得客户代码可以一致地(复用)处理对象和对象容器,无需关心处理的是单个对象,还是组合对象。
将“客户代码与复杂的对象容器结构”解耦,是Composite的核心思想,解耦之后,客户代码将与纯粹的抽象接口--而非对象容器的内部实现结构--发生依赖,从而更能应对变化。
Composite模式在具体实现中,可以让父对象中的子对象反向追溯;如果父对象有频繁的遍历需求,可以使用缓存技巧来改善效率。