23种设计模式之11.组合模式

142 阅读2分钟

组合模式是用于把一组相似的对象组合为一个对象。将对象组合成树形结构以表示“部分-整体”的层次结构。它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。例如windows中的文件夹及时一种组合模式,一个文件夹下可能包含多个文件夹,每个文件夹又有可能包含其他的文件夹。

下面使用代码来演示文件夹的例子。

首先有一个文件夹的类,文件夹的属性先不考虑其他,只有一个名称和一个子文件列表。

public class Folder {

    private String name;
    private List<Folder> folderList;

    public Folder(String name) {
        this.name = name;
        this.folderList = new ArrayList<>();
    }

    /**
     * 添加子文件夹
     * @param folder 子文件夹对象
     */
    public void addSubFolder(Folder folder){
        folderList.add(folder);
    }

    public List<Folder> getFolderList() {
        return folderList;
    }

    @Override
    public String toString() {
        return name;
    }
}

初始化6个文件夹,按照一级文件夹中二级文件夹,二级文件夹中是三级文件夹的规则将这6个文件夹组合起来,编写一个打印函数按照层级结构递归打印出文件夹的层次结构。

public class Main {
    public static void main(String[] args) {

        Folder folder1_1 = new Folder("一级文件夹");
        Folder folder2_1 = new Folder("二级文件夹_1");
        Folder folder2_2 = new Folder("二级文件夹_2");
        Folder folder3_1 = new Folder("三级文件夹_1");
        Folder folder3_2 = new Folder("三级文件夹_2");
        Folder folder3_3 = new Folder("三级文件夹_3");

        folder2_1.addSubFolder(folder3_1);
        folder2_1.addSubFolder(folder3_2);
        folder2_2.addSubFolder(folder3_3);
        folder1_1.addSubFolder(folder2_1);
        folder1_1.addSubFolder(folder2_2);

        printFolder(folder1_1,-1);

    }

    private static void printFolder(Folder folder ,int level){
        level++;
        for (int i = 0; i < level; i++) {
            System.out.print("   ");
        }
        System.out.println(folder.toString());
        for (Folder subFolder: folder.getFolderList()) {
            printFolder(subFolder,level);
        }
    }
}

运行结果如下图所示:

image.png

组合模式就是一种树形结构,与数据结构中的多叉树的结构都是一致的,使用中可按照自己的需求对每个节点增加属性,但是大体的结构都是相似的。

组合模式优点:

  1. 高层节点的调用简单,下层节点都可以从高层节点的关系中找到。

  2. 使用灵活,可以自由的组织节点之间的关系。

组合模式缺点:

  1. 在使用组合模式时,节点的声明都是实现类,而不是接口,违反了依赖倒置原则。

  2. 设计较复杂,使用者需要组织结构关系,当下级节点的子节点引用了上级节点时会出现环状结构,导致递归时无法退出。

  3. 子节点不容易被限制。