共计 2523 个字符,预计需要花费 7 分钟才能阅读完成。
前言
本系列文章主要根据《JavaScript 设计模式与开发实践》整理而来,其中会加入了一些自己的思考。希望对大家有所帮助。
文章系列
js 设计模式 – 单例模式
js 设计模式 – 策略模式
js 设计模式 – 代理模式
js 设计模式 – 迭代器模式
js 设计模式 – 发布订阅模式
js 设计模式 – 命令模式
概念
组合模式就是用小的子对象来构建更大的对象,而这些小的子对象本身也许是由更小的“孙对象”构成的。
场景
组合模式除了要求组合对象和叶对象拥有相同的接口之外,还有一个必要条件,就是对一组叶对象的操作必须具有一致性。
优缺点
优点
组合模式将对象组合成树形结构,以表示“部分 - 整体”的层次结构。除了用来表示树形结 构之外,组合模式的另一个好处是通过对象的多态性表现,使得用户对单个对象和组合对象的使 用具有一致性
缺点
它可能会产生一个这样的系统: 系统中的每个对象看起来都 与其他对象差不多。它们的区别只有在运行的时候会才会显现出来,这会使代码难以理解。此外,如果通过组合模式创建了太多的对象,那么这些对象可能会让系统负担不起。
例子
扫描文件夹
这里把文件和文件夹无区别对待,文件和文件夹都具有 add 和 scan 方法
var 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 (var i = 0, file, files = this.files; file = files[i++];) {
file.scan();
}
};
/******************************* File ******************************/
var File = function (name) {
this.name = name;
};
File.prototype.add = function () {
throw new Error(‘ 文件下面不能再添加文件 ’);
};
File.prototype.scan = function () {
console.log(‘ 开始扫描文件: ‘ + this.name);
};
var folder = new Folder(‘ 学习资料 ’);
var folder1 = new Folder(‘JavaScript’);
var folder2 = new Folder(‘jQuery’);
var file1 = new File(‘JavaScript 设计模式与开发实践 ’);
var file2 = new File(‘ 精通 jQuery’);
var file3 = new File(‘ 重构与模式 ’)
folder1.add(file1);
folder2.add(file2);
folder.add(folder1);
folder.add(folder2);
folder.add(file3);
var folder3 = new Folder(‘Nodejs’);
var file4 = new File(‘ 深入浅出 Node.js’);
folder3.add(file4);
var file5 = new File(‘JavaScript 语言精髓与编程实践 ’);
folder.add(folder3);
folder.add(file5);
folder.scan();
增加删除方法
我们需要增加一个父对象的引用
var Folder = function (name) {
this.name = name;
this.parent = null; // 增加 this.parent 属性
this.files = [];
};
Folder.prototype.add = function (file) {
file.parent = this; // 设置父对象
this.files.push(file);
};
Folder.prototype.scan = function () {
console.log(‘ 开始扫描文件夹: ‘ + this.name);
for (var i = 0, file, files = this.files; file = files[i++];) {
file.scan();
}
};
Folder.prototype.remove = function () {
if (!this.parent) {// 根节点或者树外的游离节点
return;
}
for (var files = this.parent.files, l = files.length – 1; l >= 0; l–) {
var file = files[l];
if (file === this) {
files.splice(l, 1);
}
}
};
var File = function (name) {
this.name = name;
this.parent = null;
};
File.prototype.add = function () {
throw new Error(‘ 不能添加在文件下面 ’);
};
File.prototype.scan = function () {
console.log(‘ 开始扫描文件: ‘ + this.name);
};
File.prototype.remove = function () {
if (!this.parent) {// 根节点或者树外的游离节点
return;
}
for (var files = this.parent.files, l = files.length – 1; l >= 0; l–) {
var file = files[l];
if (file === this) {
files.splice(l, 1);
}
}
};
var folder = new Folder(‘ 学习资料 ’);
var folder1 = new Folder(‘JavaScript’);
var file1 = new Folder(‘ 深入浅出 Node.js’);
folder1.add(new File(‘JavaScript 设计模式与开发实践 ’));
folder.add(folder1);
folder.add(file1);
folder1.remove(); // 移除文件夹
folder.scan();