首页 组合模式
文章
取消

组合模式

组合模式的原理和实现

定义

组合模式跟之前讲的面向对象设计中的“组合关系(通过组合来组装两个类)”,完全是两码事。这里讲的“组合模式”,主要是用来处理树形结构数据。这里的“数据”,可以简单理解为一组对象集合,它的定义如下:

将一组对象组织(Compose)成树形结构,以表示一种“部分-整体”的层次结构。组合让客户端(在很多设计模式书籍中,“客户端”代指代码的使用者。)可以统一单个对象和组合对象的处理逻辑。

光看定义不知所云,下面举个例子翻译一下:

假设我们有这样一个需求:设计一个类来表示文件系统中的目录,能方便地实现下面这些功能:

  1. 动态地添加、删除某个目录下的子目录或文件;
  2. 统计指定目录下的文件个数;
  3. 统计指定目录下的文件总大小。

下面是骨架代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * 目录/文件节点
 */
public class FileSystemNode {
    private String path;
    private boolean isFile;
    private List<FileSystemNode> subNodes = new ArrayList<>();

    public FileSystemNode(String path, boolean isFile) {
        this.path = path;
        this.isFile = isFile;
    }

    public int countNumOfFiles() {
        if (isFile) {
            return 0;
        }
        return countNumOfFiles(0, this);
    }

    /**
     * 这才是递归,虽然放在这个类里面不合适(放在一个公共类里面会更合适,或者是作为静态方法),毕竟这个方法除了计算当前节点还能计算其他节点
     * @param num
     * @param node
     */
    public int countNumOfFiles(int num, FileSystemNode node) {
        if (node.isFile) {
            return 1;
        }
        for (FileSystemNode systemNode : node.getSubNodes()) {
            num += countNumOfFiles(0, systemNode);
        }
        return num;
    }

    /**
     * 这个方法不叫递归哈
     */
    public long countSizeOfFiles() {
        if (isFile) {
            File file = new File(path);
            if (!file.exists()) return 0;
            return file.length();
        }
        long sizeofFiles = 0;
        for (FileSystemNode fileOrDir : subNodes) {
            sizeofFiles += fileOrDir.countSizeOfFiles();
        }
        return sizeofFiles;
    }

    public String getPath() {
        return path;
    }

    public List<FileSystemNode> getSubNodes() {
        return subNodes;
    }

    public void addSubNode(FileSystemNode fileOrDir) {
        subNodes.add(fileOrDir);
    }

    public void removeSubNode(FileSystemNode fileOrDir) {
        int size = subNodes.size();
        int i = 0;
        for (; i < size; ++i) {
            if (subNodes.get(i).getPath().equalsIgnoreCase(fileOrDir.getPath())) {
                break;
            }
        }
        if (i < size) {
            subNodes.remove(i);
        }
    }
}

在上面这段代码中,对于文件直接返回文件的个数/大小,对于目录就去遍历内部的子目录和文件,递归计算它们的个数/大小,然后求和。

对照着定义:将一组对象(目录/文件构成的节点)组织成树形结 构,以表示一种‘部分-整体’的层次结构(节点与子节点)。组合模式让客户端可 以统一单个对象(目录/文件)和组合对象(节点)的处理逻辑(递归遍历)

其实这里的组合对象从算法与数据结构的角度来看就是开发者自定义的新的数据结构(其满足树形结构的特点)。

本文由作者按照 CC BY 4.0 进行授权

导入导出注解式解决方案

迁移Postgres的Sequence(序列)