组合模式就是用小的子对象来构建更大的对象,而这些小的子对象本身也许是由更小的“孙对象”构成的。
1.组合模式的用途
(1)表示树形结构。
(2)利用对象多态性统一对待组合对象和单个对象。
2.请求在组合树中的传递过程
请求从树最顶端的对象往下传递,如果当前处理请求的对象是叶对象,叶对象自身会对请求作出相应的处理;如果当前处理请求的对象是组合对象,组合对象则会遍历它属下的子节点,将请求继续传递给这些子节点。
3.组合模式的基本实现
下面用一个扫描文件夹的实例来演示组合模式
let Folder = function (name) { //定义文件夹类
this.name = name;
this.files = [];
}
Folder.prototype.add = function (file) { //添加文件
this.files.push(file);
}
Folder.prototype.scan = function () { //扫描文件夹
console.log('扫描文件夹: ' + this.name);
for (let i = 0, file; file = this.files[i++];) {
file.scan();
}
}
let File = function (name) { //定义文件类
this.name = name;
}
File.prototype.add = function () { //添加文件
throw new Error('文件下面不能再添加文件');
}
File.prototype.scan = function () { //扫描文件
console.log('扫描文件: ' + this.name);
}
let folder = new Folder('文件夹');
let folder1 = new Folder('文件夹1');
let folder2 = new Folder('文件夹2');
let file = new File('文件');
let file1 = new File('文件1');
let file2 = new File('文件2');
folder1.add(file);
folder2.add(file1);
folder.add(folder1);
folder.add(folder2);
folder.add(file2);
folder.scan();
以上代码实现了一个基本的组合模式,用户在使用扫描操作的时候,无需关心当前文件夹下的树结构,以及子文件夹和子文件的数量,且如果操作内容进行了改动,不需要在源代码上进行任何改动,它仍然能够按照原定行为进行操作。
4.使用组合模式的注意点
(1)组合模式不是父子关系。组合模式是一种HAS-A(聚合)的关系,组合对象包含一组叶对象,但叶对象并不是组合对象的子类。组合对象把请求委托给它所包含的所有叶对象,它们能合作的关键是拥有相同的接口。
(2)对一组叶对象的操作必须具有一致性。
(3)双向映射关系。如果对象之间的关系并不是严格意义上的层次结构,通常是不适合使用组合模式的。除非对父节点和子节点建立双向映射关系。
(4)使用职责链模式提高组合模式性能
5.什么时候使用组合模式
(1)表示对象的部分-整体层次结构。
(2)客户希望统一对待树中的所有对象。