定義
又叫做部分-整體模式,它使我們樹形結構的問題中,模糊了簡單元素和複雜元素的概念,客戶程序可以像處理簡單元素一樣來處理複雜元素,從而使得客戶程序與複雜元素的內部結構解耦。
要點
- 組合對象、葉對象:組合對象並不執行真正的操作,而是遍歷它所包含的葉對象,把真正的請求委託給這些葉對象。
- 組合模式將對象組合成樹形結構,提供了一種深度優先遍歷樹形結構的方案。
- 組合模式利用對象多態性統一對待組合對象和單個對象,使客戶端忽略兩者的不同。
- JavaScript作為一種動態類型語言,實現組合模式的難點在於要保證組合對象和葉對象擁有同樣的方法,這通常需要用鴨子類型的思想(關注對象的行為,而不關注對象本身)對它們進行接口檢查。
- 葉對象是沒有子節點的。對於視圖往葉對象中添加子節點的誤操作,解決方案通常是給葉對象也添加 add 方法,並且在調用這個方法時,拋出一個異常來及時提醒客戶。
- 組合對象保存了它的子節點的引用,這是組合模式的特點,樹結構是從上至下的;有時也需要在子節點上保持對父節點的引用,比如刪除某個文件時,實際上是從文件所在的上層文件夾中刪除該文件。
- 組合對象和葉對象不是父子關係。組合對象把請求委託給它所包含的所有葉對象,它們能夠合作的關鍵是具有相同的接口。另外,對一組葉對象的操作必須具有一致性。
- 文件夾和文件之間的關係,非常適合用組合模式來描述。
核心代碼
// 文件夾和文件
var Folder = function(name) {
this.name = name;
this.files = [];
this.parent = null;
};
Folder.prototype.add = function(file) {
this.files.push(file);
file.parent = this;
};
Folder.prototype.scan = function() {
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(file) {
throw new Error('不能添加在文件下面');
};
File.prototype.scan = function() {
// ......
};
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);
}
}
};
网友评论