組合模式

定義

又叫做部分-整體模式,它使我們樹形結構的問題中,模糊了簡單元素和複雜元素的概念,客戶程序可以像處理簡單元素一樣來處理複雜元素,從而使得客戶程序與複雜元素的內部結構解耦。

要點

  • 組合對象、葉對象:組合對象並不執行真正的操作,而是遍歷它所包含的葉對象,把真正的請求委託給這些葉對象。
  • 組合模式將對象組合成樹形結構,提供了一種深度優先遍歷樹形結構的方案。
  • 組合模式利用對象多態性統一對待組合對象和單個對象,使客戶端忽略兩者的不同。
  • 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);
        }
    }
};

你可能感兴趣的:(組合模式)