这是一个结构型模式,对象的结构模式描述了怎样把各种不同类型的对象组合在一起,以实现新功能的方法。可以在运行时刻改变对象组合关系,对象的结构模式是动态的。
面临问题:
我们可以使用简单的对象组合成复杂的对象,而这个复杂对象有可以组合成更大的对象。我们可以把简单这些对象定义成类,然后定义一些容器类来存储这些简单对象。客户端代码必须区别对象简单对象和容器对象,而实际上大多数情况下用户认为它们是一样的。对这些类区别使用,使得程序更加复杂。递归使用的时候跟麻烦,而我们如何使用递归组合,使得用户不必对这些类进行区别呢?
也就是说,我们如何将“客户代码与复杂的对象容器结构”解耦?让对象容器自己来实现自身的复杂结构,从而使得客户代码就像处理简单对象一样来处理复杂的对象容器?
解决方案:
将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
举个例子:文件系统由目录和文件组成。每个目录都可以装内容。目录的内容可以是文件,也可以是目录。按照这种方式,计算机的文件系统就是以递归结构来组织的。如果你想要描述这样的数据结构,那么你可以使用组合模式。这样,客户可以将对象的集合和个人的对象一视同仁。
注意上图中的leaf和composite都是通过继承实现的,这样保证了都是同样的类型。
组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器,而客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。
同时容器对象与抽象构件类之间还建立一个聚合关联关系,在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成一个树形结构。
典型的Composite角色代码:
public class Composite extends Component
{
private ArrayList list = new ArrayList();//定义了一个list,用来存放子节点。因为其实composite实例化的对象是一个组合对象。
public void add(Component c)
{
list.add(c);//增加节点。
}
public void remove(Component c)
{
list.remove(c);//删除节点
}
public Component getChild(int i)
{
(Component)list.get(i);//获得组合对象的第几个节点。
}
public void operation()
{
for(Object obj:list)
{
((Component)obj).operation();//遍历所有孩子的所有操作,是个递归的过程。
}
}
}
应用举例:
一个绘图系统给出各种工具用来描绘由线、长方形和圆形等基本图形组成的图形。
设计应当包括Line、Rectangle和Circle等对象,而且每一个对象都应当配备有一个draw()方法,在调用时会画出对象所代表的图形。
由于一个复杂的图形是由基本图形组合而成的,因此,一个组合的图形应当有一个列表,存储对所有的基本图形对象的引用。复合图形的draw()方法在调用时,应当逐一调用所有列表上的基本图形对象的draw()方法。
相关的模式:
Decorator经常和Composite一起使用,通常有一个公共的父类
Flyweight可以共享组件但是不再能引用他们的父类对象
Iterator:可用来遍历Composite
Visitor:将本来应该分布在Composite和Leaf类中的操作和行为局部化