組合模式的作用
組合模式將對象組成樹形結(jié)構(gòu)毕箍,以表示'整體-部分'的結(jié)構(gòu)。利用對象的多態(tài)性統(tǒng)一對待組合對象和單個對象皆辽。
樹結(jié)構(gòu)的節(jié)點分為組合節(jié)點和葉節(jié)點萨赁。葉節(jié)點下面不會再有節(jié)點弊琴,組合節(jié)點下面可能還有其他組合節(jié)點和葉節(jié)點。
什么時候使用組合模式
- 表示對象的部分-整體層次結(jié)構(gòu)杖爽。
- 客戶希望統(tǒng)一對待樹中的所有對象敲董。
例子:掃描文件夾
//folder是組合節(jié)點
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;i<this.files.length;i++) {
this.files[i].scan();
}
}
//file是葉節(jié)點
var File=function(name) {
this.name=name;
}
File.prototype.add =function() {
throw new Error('文件下面不能再添加文件');
}
File.prototype.scan=function() {
console.log('當(dāng)前文件名:',this.name);
}
//使用
var folder1=new Folder('所有資料');
var folder2=new Folder('生活資料');
var folder3=new Folder('工作資料');
var file1=new File('數(shù)學(xué)');
var file2=new File('語文');
var file3=new File('鉆木取火');
var file4=new File('nodeJs從入門到放棄');
folder1.add(file1);
folder1.add(file2);
folder2.add(file3);
folder3.add(file4);
folder1.add(folder2);
folder1.add(folder3);
folder1.scan();
值得注意的地方
- 組合模式不是父子關(guān)系,而是一種(HAS-A)聚合關(guān)系慰安。
- 對一組葉對象的操作必須具有一致性腋寨。也就是說不能對某個葉對象單獨操作,要一視同仁化焕。
- 為?防止一個葉節(jié)點關(guān)聯(lián)到多個組合對象萄窜,需要建立組合節(jié)點和葉節(jié)點的雙向映射關(guān)系。
保持葉節(jié)點和組合節(jié)點的關(guān)聯(lián)撒桨。比如在組合模式中使用職責(zé)鏈時脂倦,有可能需要讓請求從子節(jié)點往父節(jié)點上冒泡傳遞。當(dāng)我們刪除某個文件時元莫,實際是從這個文件所在的上層文件夾中刪除這個文件。
var Folder=function(name) {
this.name=name;
this.parent=null;
this.files=[];
}
Folder.prototype.add=function(file) {
this.files.push(file);
file.parent=this;
}
Folder.prototype.scan=function() {
console.log('開始掃描文件夾:',this.name);
for (var i=0;i<this.files.length;i++) {
this.files[i].scan();
}
}
Folder.prototype.rmove=function() {
//根節(jié)點
if (!this.parent) {
return;
}
for (var files=this.parent.files,i=files.length-1;i>=0;i--) {
var file=files[i];
if (file===this) {
files.splice(i,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,i=files.length-1;i>=0;i--) {
var file=files[i];
if (file===this) {
files.splice(i,1);
}
}
}