定义
组合模式就是用小的子对象来构建更大的对象,而这些小的子对象本身也许是由更小的“孙对象”构成的。——《JavaScript设计模式与开发实践》
组合模式是一个树状的结构,其所有的节点实现了相同的接口(execute、add),组合节点的execute方法会去遍历子节点,调用其execute方法。 这就使得用户可以仅调用根节点,就可以将所有叶子节点的execute方法执行,且无需对节点进行判断(是否是叶子节点)。
使用场景
1、表示对象的部分-整体层次结构。只需要通过请求树的最顶层对象,便能对整棵树做统一的操作。
实现示例
// 组合节点
class Composite {
constructor() {
this.children = [];
this.parent = null;
}
addChild(child) {
this.children.push(child);
child.parent = this;
}
removeChild(child) {
child.parent = null;
const index = this.children.findIndex(c => c === child);
this.children.splice(index, 1);
}
execute() {
this.children.forEach(child => {
child.execute();
});
}
}
// 叶子节点
class Leaf {
constructor() {
this.parent = null;
}
addChild(child) {
throw new Error('叶对象不能添加子节点');
}
removeChild(child) {
throw new Error('叶对象不能移除子节点');
}
execute() {
}
}
可以看到组合节点跟叶子节点实现了相同的接口(addChild、removeChild、execute),addChild、removeChild方法用于动态地构建树结果,且子节点的addChild、removeChild方法做了相应的限制。而在execute方法中,组合节点只会遍历并执行他子节点的execute方法,这样就能一层层透传知道叶子节点。这样就能达到,在根节点调用execute方法,而执行其所有叶子节点execute方法的效果,且不用对节点的类型进行判断。
示例演示
// 一个读取文件的示例
class Folder extends Composite {
constructor(folderName) {
super();
this.folderName = folderName;
}
execute() {
console.log(this.folderName + ' is opening...');
super.execute();
}
}
class File extends Leaf {
constructor(fileName) {
super();
this.fileName = fileName;
}
execute() {
console.log(this.fileName + ' is reading...');
}
}
const folderRoot = new Folder('folderRoot');
const folder1 = new Folder('folder1');
const folder2 = new Folder('folder2');
const folder3 = new Folder('folder3');
const file1 = new File('file1');
const file2 = new File('file2');
const file3 = new File('file3');
const file4 = new File('file4');
folderRoot.addChild(folder1);
folderRoot.addChild(file1);
folder1.addChild(file2);
folder1.addChild(file3);
folder1.addChild(folder2);
folder1.addChild(folder3);
folder3.addChild(file4);
folderRoot.execute();
folder1.removeChild(folder3);
folderRoot.execute();
运行结果如下