数据结构中有一种结构是树,树包含根节点、子节点、叶子结点,而组合模式就是专门用来处理类似树结构的设计模式,组成这棵树的节点和叶子是一个个对象,而组合模式却可以以统一对待叶子和节点。
要想统一对待,在面向对象中很难不想到抽象二字,只有站的高,面向高层处理,才有底气屏蔽底层细节,增加扩展性。
举个栗子:
平常我们用的windows文件夹就是树结构的,文件夹里可以包含文件夹,文件夹里可以包含文件,这里文件夹代表容器,也就是节点,文件就代表叶子结点,不可包含其他。
组合模式UML类图如下所示:
解释:Folder和File_是Compotent的子类容易理解,但但Component和Folder的关联聚合关系怎么理解呢?Component是Folder和File_的抽象,但在这个树状结构中,Folder既能包含Folder,又能包含File_,也就是Folder包含他们的共同父类Component:Folder contains Conponent,体现在类图中的就是聚合关系。
下面以读取文件夹为例写一个组合模式实例小程序,注意读取文件夹会把他下面所有文件夹带文件读取一遍。
抽象组件类:
/****
* 抽象组件类,文件夹和文件的抽象类
* @author wjw
*
*/
public abstract class Component {
public abstract void addComponent(Component component);
public abstract void deleteComponent(Component component);
public abstract Component getChild(int i);
public abstract void read();
}
文件夹类:
public class Folder extends Component{
private String folderName;
private List<Component> components = new ArrayList<Component>();
public Folder(String folderName){
this.folderName = folderName;
}
@Override
public void addComponent(Component component) {
// TODO Auto-generated method stub
components.add(component);
}
@Override
public void deleteComponent(Component component) {
// TODO Auto-generated method stub
components.remove(component);
}
@Override
public Component getChild(int i) {
// TODO Auto-generated method stub
return components.get(i);
}
@Override
public void read() {
// TODO Auto-generated method stub
System.out.println("读取=="+folderName+"==文件夹!");
System.out.println("----begin "+folderName+"----");
for (Component component : components) {
component.read();
}
System.out.println("----end "+folderName+"----");
}
}
文件类:
public class File_ extends Component{
private String fileName;
public File_(String fileName){
this.fileName = fileName;
}
@Override
public void addComponent(Component component) {
// TODO Auto-generated method stub
System.out.println("文件中不允许添加文件!");
}
@Override
public void deleteComponent(Component component) {
// TODO Auto-generated method stub
System.out.println("文件中不允许删除文件!");
}
@Override
public Component getChild(int i) {
// TODO Auto-generated method stub
System.out.println("文件中不允许读取文件!");
return null;
}
@Override
public void read() {
// TODO Auto-generated method stub
System.out.println("读取--"+fileName+"--文件!");
}
}
Main类:
public class Main {
public static void main(String[] args) {
Component c1 = new Folder("C盘");
Component c2 = new Folder("系统文件夹");
Component c3 = new Folder("应用程序文件夹");
Component c3_1 = new Folder("QQ文件夹");
Component c3_2 = new Folder("MYSQL文件夹");
Component c3_3 = new Folder("MSN文件夹");
Component c4 = new Folder("资料文件夹");
Component c4_1 = new Folder("音乐文件夹");
Component c4_1_1 = new File_("海阔天空.mp3");
Component c4_2 = new Folder("图片文件夹");
Component c4_2_1 = new File_("aaa.jpg");
Component c4_2_2 = new File_("bbb.png");
c1.addComponent(c2);
c1.addComponent(c3);
c1.addComponent(c4);
c3.addComponent(c3_1);
c3.addComponent(c3_2);
c3.addComponent(c3_3);
c4.addComponent(c4_1);
c4.addComponent(c4_2);
c4_1.addComponent(c4_1_1);
c4_2.addComponent(c4_2_1);
c4_2.addComponent(c4_2_2);
c1.read();
}
}
运行结果:
读取==C盘==文件夹!
----begin C盘----
读取==系统文件夹==文件夹!
----begin 系统文件夹----
----end 系统文件夹----
读取==应用程序文件夹==文件夹!
----begin 应用程序文件夹----
读取==QQ文件夹==文件夹!
----begin QQ文件夹----
----end QQ文件夹----
读取==MYSQL文件夹==文件夹!
----begin MYSQL文件夹----
----end MYSQL文件夹----
读取==MSN文件夹==文件夹!
----begin MSN文件夹----
----end MSN文件夹----
----end 应用程序文件夹----
读取==资料文件夹==文件夹!
----begin 资料文件夹----
读取==音乐文件夹==文件夹!
----begin 音乐文件夹----
读取--海阔天空.mp3--文件!
----end 音乐文件夹----
读取==图片文件夹==文件夹!
----begin 图片文件夹----
读取--aaa.jpg--文件!
读取--bbb.png--文件!
----end 图片文件夹----
----end 资料文件夹----
----end C盘----
组合模式说明:
如果我们程序要处理的是一个树形结构,且忽略整体与部分差异,可以考虑组合模式合适不合适。这里我们组件就两个,分的不太细,在具体编程中,也许组件种类很多,比如文件夹类型分为系统文件夹,普通文件夹,文件类型分为图片文件、文本文件、音频文件、视频文件等。这时我们面向抽象的优点再次显现出来了。对扩展开放。
总而言之,组合模式处理树
如有错误,欢迎指正
end