《JavaScript设计模式与开发实践》——学习笔记(组合模式)

132 阅读2分钟

定义

组合模式就是用小的子对象来构建更大的对象,而这些小的子对象本身也许是由更小的“孙对象”构成的。——《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();

运行结果如下