组合模式允许开发者将对象组合成树形结构来表现"部分-整体"的层次结构。这种模式使得客户端可以统一地对待单个对象和组合对象。
// 组件接口
class FileSystemComponent {
constructor(name) {
this.name = name;
}
display(indent = '') {
throw new Error('Method not implemented');
}
getSize() {
throw new Error('Method not implemented');
}
isDirectory() {
return false;
}
}
// 叶子节点:文件
class File extends FileSystemComponent {
#size;
constructor(name, size) {
super(name);
this.#size = size;
}
display(indent = '') {
console.log(`${indent}File: ${this.name} (${this.#size} bytes)`);
}
getSize() {
return this.#size;
}
}
// 复合节点:目录
class Directory extends FileSystemComponent {
#children;
constructor(name) {
super(name);
this.#children = [];
}
add(component) {
this.#children.push(component);
}
remove(component) {
const index = this.#children.indexOf(component);
if (index !== -1) {
this.#children.splice(index, 1);
}
}
display(indent = '') {
console.log(`${indent}Directory: ${this.name}`);
this.#children.forEach(child => child.display(indent + ' '));
}
getSize() {
return this.#children.reduce((sum, child) => sum + child.getSize(), 0);
}
isDirectory() {
return true;
}
findChild(name) {
return this.#children.find(child => child.name === name);
}
}
// 文件系统类
class FileSystem {
#root;
constructor() {
this.#root = new Directory('Root');
}
addComponent(component, path = []) {
let currentDir = this.#root;
for (const dirName of path) {
let dir = currentDir.findChild(dirName);
if (!dir || !dir.isDirectory()) {
dir = new Directory(dirName);
currentDir.add(dir);
}
currentDir = dir;
}
currentDir.add(component);
}
display() {
this.#root.display();
}
getTotalSize() {
return this.#root.getSize();
}
}
// 使用示例
const fileSystem = new FileSystem();
fileSystem.addComponent(new File('document.txt', 100));
fileSystem.addComponent(new File('image.jpg', 2000));
fileSystem.addComponent(new Directory('Empty Directory'));
fileSystem.addComponent(new File('config.json', 50), ['config']);
fileSystem.addComponent(new File('logo.png', 1000), ['images']);
fileSystem.addComponent(new File('script.js', 200), ['src', 'js']);
fileSystem.addComponent(new File('style.css', 150), ['src', 'css']);
console.log("File System Structure:");
fileSystem.display();
console.log(`\nTotal Size: ${fileSystem.getTotalSize()} bytes`);
实现思路
-
FileSystemComponent类:这是组件的抽象基类,定义了文件系统中所有元素的通用接口。isDirectory()方法,默认返回false。 -
File类:这是叶子节点,代表文件系统中的文件。它有具体的大小,并且不能包含其他组件。 -
Directory类:这是复合节点,代表文件系统中的目录。它可以包含其他文件或目录。- 使用私有字段
#children来存储子组件。 - 实现了
add和remove方法来管理子组件。 - 重写
isDirectory()方法,返回true。 - 添加了
findChild(name)方法,用于在目录中查找子组件。
- 使用私有字段
-
FileSystem类:这是客户端使用的主要类,封装了整个文件系统的结构。- 使用私有字段
#root来存储根目录。 - 提供了
addComponent方法,允许在任意路径添加新的组件。 - 实现了
display和getTotalSize方法来展示结构和计算总大小。
- 使用私有字段
优点
- 统一接口:客户端可以统一地处理简单和复杂的元素。
- 简化客户端代码:客户端不需要知道是在处理叶子节点还是复合节点。
- 易于添加新类型的组件:可以轻松扩展新的文件类型或特殊目录。
- 创建复杂的树结构:可以用来表示任意复杂的层次结构。