定义
在对单个对象的处理中,可以以简单明了的方式进行,即按照需求正常进行操作即可。当待操作的对象不是单个对象,而是一个对象集合时,因为实际需要操作的目标是集合的元素,所以在执行目标对象行为之前,需要进行定位目标对象的额外操作(例如遍历集合)。如果把集合作为为了实现目标行为(即多个对象的行为调用)而附加的一个属性,则需要提供对该属性的管理。
示例
例如上图,想要完成的需求是提供“共享”、“新建”、“删除”等功能,为了实现对多个功能点管理的方便,所以将这几个功能保存在“文件”的集合中(即一个下拉菜单,而不是一排按钮),所以也就需要提供对集合的管理操作。
仍然以上图为例,在“文件”的集合中保存有两种类型的元素:
1、在“新建”之中又保存有一个集合,提供“文件夹”、“快捷方式”等子功能,此时“新建”是“文件”集合中的元素,同时自身也是集合类型;
2、“删除”不是一个集合,只是一个单纯的元素类型,这里为了向树形结构靠拢,也称此类型为叶子类型
问题
此时问题出现了,客户端需要面对的是两种类型的对象,为了实施要完成的目标对象行为,在定位到目标对象的过程中需要判断当前处理的对象是集合类型还是叶子类型,即客户端对对象的结构需要“关心”,处理的复杂度增加,而且没有做到松耦合。
组合结构
为了使客户端在处理对象时可以忽略其内部结构的差异,此处引入组合模式,提供抽象的构件类,在抽象构建类中提供公共访问方法,满足客户端的统一访问,屏蔽了叶子类型与集合类型(也可以说是整体与部分)的不同。
由此可知,组合模式包括三个部分:
1、抽象构建,表达客户端操作的对象,提供访问接口,屏蔽叶子和集合的差异(其实已经有偏向了)
2、叶子类型,不具有集合属性,直接提供操作行为
3、集合类型,本身是一个集合对象,实现了集合管理操作,操作行为实现为递归调用集合元素的操作
根据实现形式不同,存在的问题有:
1、如果待操作对象属于集合类型,则需要提供对集合的操作,即抽象构件类中需要持有对集合的管理行为,默认保持了集合类型的特性,而在叶子类型对象中则需要对这些行为进行覆盖,声明不支持或者抛出异常,如图
在抽象类中声明集合管理操作,但是声明为不支持(替叶子类型考虑),在Leaf叶子类型中直接覆盖Operation即可,在Composite集合类中覆盖管理操作与Operation。
2、如果将抽象类保持叶子类型的特性,则对集合的管理行为需要在具体集合类中实现,此时客户端需要对具体集合类编程
在具体集合类中添加集合管理操作,则客户端需要在使用集合对象时声明Composite类型对象,即操作对客户端不透明。
以第一种作为示例,参考代码
public class t{
public static void main(String[] args){
Component file=new Composite("file");//“文件”菜单
Component delete,rename,new_built;//“文件”下拉列表:“删除”、“重命名”、“新建”
Component txt,word;//“新建”子列表:“文本文档”、“word文档”
//三个第一级子菜单选项
delete=new Leaf("delete");
rename=new Leaf("rename");
new_built=new Composite("new_built");
file.Add(delete);
file.Add(rename);
file.Add(new_built);
//两个第二级子菜单选项
txt=new Leaf("txt");
word=new Leaf("word");
new_built.Add(txt);
new_built.Add(word);
//测试方法
file.Operation();
}
}
abstract class Component{//抽象公共类
public void Add(Component c){//为了避免叶子节点的重写
System.out.println("not supported");
}
public void Remove(Component c){
System.out.println("not supported");
}
abstract void Operation();
}
class Leaf extends Component{//叶子类型对象
private String name=null;
public Leaf(String name){
this.name=name;
}
public void Operation(){
System.out.println(this.name+" operated");
}
}
class Composite extends Component{
private String name=null;
private List<Component> arr=new ArrayList<Component>();
public Composite(String name){
this.name=name;
}
public void Add(Component c){//集合对象重写管理操作
arr.add(c);
}
public void Remove(Component c){
arr.remove(c);
}
public void Operation(){
System.out.println(this.name+" operated");
System.out.println("\n"+this.name+" folder operated----");
Iterator<Component> it=arr.iterator();
while(it.hasNext()){
it.next().Operation();
}
}
}
总结
组合模式适用于处理整体-部分对象关系,用以提供一种无差别的对象访问方式,且弱化了客户端与对象结构的关联关系,并且属于面向抽象操作,即不仅降低了处理的复杂程度,同样降低了耦合度。