什么是组合模式
将对象组合成属性结构以表示“部分-整体”的层次结构。组合使得用户和单个对象和组合对象的使用具有一致性。
组合对象的角色
1. Component:是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component.
2. Leaf:在组合中表示叶子节点对象,叶子节点没有子节点。
3. Composite:定义树枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加和删除等。
组合模式的结构有点类似于树状结构:
模式定义中的组合是指连接节点(node),单个对象是指叶子节点,一致性是指具有相同的函数方法,这个一致性有点问题,我们通过一个例子来说明
实例:文件系统
IFile:
public interface IFile {
//添加文件夹或是文件,只对Folder有效
void add(IFile file);
//删除文件夹下的所有文件,只对文件夹有效
void remove();
//输出文件(夹)的名字
void display();
//删除文件(夹)
void deletefile(IFile file);
}
Folder:
import java.util.ArrayList;
public class Folder implements IFile{
private String name;
private IFile parent=null;
private ArrayList<IFile> childs=new ArrayList<IFile>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public IFile getParent() {
return parent;
}
public void setParent(IFile parent) {
this.parent = parent;
}
public ArrayList<IFile> getChilds() {
return childs;
}
public void setChilds(ArrayList<IFile> childs) {
this.childs = childs;
}
public Folder(String name){
this(name,null);
}
public Folder(String name,IFile Parent){
this.name=name;
this.parent=Parent;
}
@Override
public void add(IFile file) {
childs.add(file);
}
@Override
public void remove() {
IFile child;
while(!childs.isEmpty()){
child=childs.get(0);
if((child instanceof Folder))
child.remove();
else
child.deletefile(child);
}
if(parent!=null){
System.out.println("删除文件夹"+name);
deletefile(this);
}
}
@Override
public void display() {
System.out.println("文件夹"+name);
for(IFile child:childs)
child.display();
}
@Override
public void deletefile(IFile file) {
((Folder)parent).getChilds().remove(file);
}
}
file:
public class File implements IFile{
private String name;
private IFile parent;
public File(String name, IFile parent) {
this.name = name;
this.parent = parent;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public IFile getParent() {
return parent;
}
public void setParent(IFile parent) {
this.parent = parent;
}
@Override
public void add(IFile file) {
throw new UnsupportedOperationException("不支持对应操作");
}
@Override
public void remove() {
throw new UnsupportedOperationException("不支持对应操作");
}
@Override
public void display() {
System.out.println("文件名:"+name);
}
@Override
public void deletefile(IFile file) {
System.out.println("删除文件"+name);
((Folder)parent).getChilds().remove(file);
}
}
public class main {
public static void main(String[] args){
IFile deal=new Folder("C:\\");
IFile movie=new Folder("电影",deal);
IFile study=new Folder("学习资料",deal);
deal.add(movie);
deal.add(study);
movie.add(new File("进击的巨人",movie));
study.add(new File("设计模式",study));
study.add(new File("python爬虫",study));
deal.display();
System.out.println("----------------------------");
study.remove();
System.out.println("----------------------------");
deal.display();
}
}
输出结果:
这里有一点矛盾,组合模式要求单个对象和组合对象的使用具有一致性,上述例子中,File类是不允许使用remove()、add()方法的,在File类中定义这两个方法是为了维护透明性(即对于用户来说,这两个对象的操作方式是一样的,用户不需要了解现在自己操作的是文件夹还是文件),但是牺牲了安全性(可能会抛出异常),我们也可以将remove()、add()方法抽象为另一个接口,但这也意味着用户需要时刻了解自己使用的是什么对象,对用户的使用造成不便,组合模式的结构决定了组合对象(可以添加子节点)与叶子对象(不能添加子节点)操作的不一致,因此,透明性与安全性是一个矛盾体,根据实际情况选择