前言
今天要介绍的设计模式是组合模式,组合模式也是结构型设计模式的一种,它主要体现了整体与部分的关系,其典型的应用就是树形结构。组合是一组对象,其中的对象可能包含一个其他对象,也可能包含一组其他对象。
组合模式
组合模式定义为:将对象组合成树形结构以表示“整体-部分”的层次结构。组合模式是单个对象和组合对象的使用具有一致性。
在使用组合模式的使用要注意以下两点:
组合中既要能包含个体,也要能包含其他组合。
要抽象出对象和组合的公共特性。
举例说明
介绍了一些基本内容,可能会还是不清楚组合模式到底是什么样的一个模式,还是老样子,举🌰说明。
在我们的家用PC电脑上的文件结构就是一个很好的例子,例如在我的电脑上有如下图所示的文件目录结构。
从root文件夹到具体的文件,一层一层的这种结构就是典型的树形结构,root是硬盘中的某个文件夹,可以理解为根节点,这个文件下下面有两个文件夹和一个文件,image-folder文件夹这种有分支的可以理解为分支节点,文件则理解为叶子节点。
为了要实现这种结构,这三种节点,我们一般的思路是,创建三个根节点、分支节点、叶子节点这三个类,但是我们发现根节点的特性其实和分支节点一样,可以理解为一类,所以我们只需要创建两个类就可以。
定义分支节点(包含根节点)的接口
复制代码
/**
* 定义分支节点(根节点)
*/
public interface IBranch {
/**
* 获得分支节点信息
* @return
*/
public String getInfo();
/**
* 增加分支节点(文件夹下还可能会有文件夹)
* @param branch
*/
public void addBranch(IBranch branch);
/**
* 增加叶子节点
* @param leaf
*/
public void addLeaf(ILeaf leaf);
/**
* 获得子集
* @return
*/
public ArrayList getChildren();
}
复制代码
具体的实现如下
复制代码
/**
* 分支节点(文件夹)
*/
public class Folder implements IBranch{
/**
* 节点名称
*/
private String name;
/**
* 子集
*/
private ArrayList children = Lists.newArrayList();
/**
* 带参数的构造方法
* @param name
*/
public Folder(String name){
this.name = name;
}
/**
* 获得分支节点信息
*
* @return
*/
@Override
public String getInfo() {
return "名称:" + name;
}
/**
* 增加分支节点(文件夹下还可能会有文件夹)
*
* @param branch
*/
@Override
public void addBranch(IBranch branch) {
children.add(branch);
}
/**
* 增加叶子节点
*
* @param leaf
*/
@Override
public void addLeaf(ILeaf leaf) {
children.add(leaf);
}
/**
* 获得子集
*
* @return
*/
@Override
public ArrayList getChildren() {
return children;
}
}
复制代码
定义叶子节点的接口
复制代码
/**
* 定义叶子节点
*/
public interface ILeaf {
/**
* 获得叶子节点的信息
* @return
*/
public String getInfo();
}
复制代码
因为叶子节点,不会有子集所以只需要一个获得描述信息的方法即可,具体的实现如下。
复制代码
/**
* 叶子节点(文件)
*/
public class File implements ILeaf {
private String name;
/**
*
* @param name
*/
public File(String name){
this.name = name;
}
/**
* 获得叶子节点的信息
*
* @return
*/
@Override
public String getInfo() {
return "名称:"+name;
}
}
复制代码
节点类已经定义完成了,所以现在可以开始组装数据了,然后将最终的数据打印出来看看是不是这个结构。
复制代码
public class ClientTest {
public static void main(String[] args) {
//定义根节点
IBranch root = new Folder("root");
//定义二级节点的文件夹
IBranch imageFolder = new Folder("image-folder");
IBranch documentFolder = new Folder("document-folder");
//定义二级节点的文件
ILeaf systemFile = new File("system-file.bat");
//定义三级节点的文件夹
IBranch pngFolder = new Folder("png-folder");
IBranch gifFolder = new Folder("gif-folder");
//定义三级节点的文件
ILeaf testHtml = new File("test.html");
ILeaf testJS = new File("test.js");
//定义四级节点的文件,两个png文件
ILeaf test1png = new File("test1.png");
ILeaf test2png = new File("test2.png");
//定义四级节点的文件3个gif文件
ILeaf my1gif = new File("my1.gif");
ILeaf my2gif = new File("my2.gif");
ILeaf my3gif = new File("my3.gif");
//填充一级文件夹
root.addBranch(imageFolder);
root.addBranch(documentFolder);
root.addLeaf(systemFile);
//填充二级图片文件夹
imageFolder.addBranch(pngFolder);
imageFolder.addBranch(gifFolder);
//填充二级文档文件夹
documentFolder.addLeaf(testHtml);
documentFolder.addLeaf(testJS);
//填充三级png图片文件夹
pngFolder.addLeaf(test1png);
pngFolder.addLeaf(test2png);
//填充三级gif图片文件夹
gifFolder.addLeaf(my1gif);
gifFolder.addLeaf(my2gif);
gifFolder.addLeaf(my3gif);
System.out.println(root.getInfo());
//打印出来
getChildrenInfo(root.getChildren());
}
/**
* 递归遍历文件
* @param arrayList
*/
private static void getChildrenInfo(ArrayList arrayList){
int length = arrayList.size();
for(int m = 0;m