← 返回题目列表

组合模式在文件系统中怎么应用?

高频 中等 第 9 / 25 题 更新于 2026/07/28
组合模式文件系统目录树递归应用场景

简化版

文件系统是组合模式的经典例子:文件是叶子节点,目录是组合节点,二者都可以抽象成文件节点。客户端可以统一调用 size()print()search() 等方法,目录内部递归处理子文件和子目录。

详细版

文件系统结构:

root/
  a.txt
  images/
    logo.png
    banner.png

抽象为:

FileNode
  FileLeaf
  DirectoryComposite

统一接口:

interface FileNode {
    long size();
    void print();
}

文件直接返回自身大小,目录返回所有子节点大小之和。

组合模式让客户端不用区分文件和目录:

FileNode root = buildFileTree();
root.print();
root.size();

完整版教学

一、文件和目录为什么适合组合模式

文件系统天然是树。

文件是终点,不包含子节点。

目录可以包含:

  • 文件;
  • 子目录;
  • 子目录里的更多文件。

这和组合模式里的 Leaf、Composite 完全对应。

二、定义统一文件节点

interface FileNode {
    String getName();
    long getSize();
    void print(String prefix);
}

文件和目录都实现这个接口。

客户端只依赖 FileNode

三、文件节点实现

class FileNodeLeaf implements FileNode {
    private final String name;
    private final long size;

    public long getSize() {
        return size;
    }

    public void print(String prefix) {
        System.out.println(prefix + name);
    }
}

文件没有子节点,逻辑很直接。

四、目录节点实现

class DirectoryNode implements FileNode {
    private final String name;
    private final List<FileNode> children = new ArrayList<>();

    public long getSize() {
        long total = 0;
        for (FileNode child : children) {
            total += child.getSize();
        }
        return total;
    }

    public void print(String prefix) {
        System.out.println(prefix + name + "/");
        for (FileNode child : children) {
            child.print(prefix + "  ");
        }
    }
}

目录把操作委托给子节点。

如果子节点还是目录,递归会继续。

五、文件系统实现中的工程问题

真实文件系统或资源树中还要考虑:

  • 路径唯一性;
  • 父子关系维护;
  • 是否允许循环引用;
  • 权限校验;
  • 大目录遍历性能;
  • 递归深度;
  • 缓存目录大小;
  • 文件变化后的缓存失效。

组合模式提供结构,但不自动解决这些工程问题。

六、常见误区与追问

文件系统是组合模式的经典类比,但真实文件系统约束更复杂。一个目录含2个文件和1个子目录时,容量统计可递归求和;符号链接却可能形成环,不能简单当普通子目录继续递归。权限、懒加载和 I/O 异常也要求遍历接口显式表达失败。

检查维度判定依据
File 叶子返回自身大小,不管理子节点
Directory 组合保存子节点并聚合结果

易错点:符号链接不是普通父子边,递归跟随前必须有环检测策略。

  • 误区:目录大小永远等于所有后代文件大小之和。 硬链接、稀疏文件和文件系统元数据会让真实语义更复杂。
  • 追问:删除目录如何处理部分失败? 应定义失败策略和结果报告,不能假设所有子节点删除都成功。
  • 误区:所有节点都应支持添加子节点。 文件叶子不具备容器语义,安全式设计可避免无效方法。
  • 追问:大目录为何需要懒加载? 一次加载百万级节点会占用大量内存并拉长首次响应。
  • 追问:怎样测试递归容量? 构造已知大小的2层树,验证叶子、子目录和根目录的聚合值。

七、加强记忆

文件系统是组合模式最经典例子:文件是叶子,目录是组合,二者统一抽象成文件节点。目录递归处理子节点,客户端统一调用,不需要关心当前节点到底是文件还是目录。