天天看點

JavaScript設計模式與開發實踐---讀書筆記(10) 組合模式

組合模式就是用小的子對象來建構更大的對象,而這些小的子對象也許是由更小的"孫對象"構成的。

組合模式将對象組合成樹形結構,以表示"部分-整體"的層次結構。

抽象類在組合模式中的作用:

組合模式最大的優點在于可以一緻地對待組合對象和基本對象。這種透明性帶來的便利,在靜态類型語言中展現的尤為明顯。

JavaScript中實作組合模式的難點在于要保證組合對象和葉對象擁有同樣的方法,這通常需要用鴨子類型的思想對它們進行接口檢查。

透明性帶來的安全問題:

組合模式的例子-掃描檔案夾

檔案夾和檔案之間的關系,非常适合用組合模式來描述。

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();
        }
    };

    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('JavaScript1');
    var file2 = new File('JavaScript2');
    var file3 = new File('JavaScript3');
    folder1.add(file1);
    folder2.add(file2);

    folder.add(folder1);
    folder.add(folder2);
    folder.add(file3);

    var folder3 = new Folder('Nodejs');
    var file4 = new File('深入淺出');
    folder3.add(file4);
    var file5 = new File('123');
    folder.add(folder3);
    folder.add(file5);

    folder.scan();      

一些值得注意的地方:

1.組合模式不是父子關系

組合模式是一種HAS-A(聚合)的關系,而不是IS-A。組合對象包含一組葉對象,但Leaf并不是Composite的子類。組合對象把請求委托給它所包含的所有葉對象,它們能夠合作的關鍵是擁有相同的接口。

2.對葉對象操作的一緻性

3.雙向映射關系

4.用職責鍊模式提高組合模式性能

引用父對象:

有時候我們需要在子節點上保持對父節點的引用,比如在組合模式中使用職責鍊時,有可能需要讓請求從子節點往父節點上冒泡傳遞。還有當我們删除某個檔案的時候,實際上從這個檔案所在的上層檔案夾中删除該檔案的。

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;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;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('JavaScript1');
    folder1.add(new File('123'));
    folder.add(folder1);
    folder.add(file1);
    folder1.remove();
    folder.scan();      

何時使用組合模式:

  • 表示對象的部分-整體層次結構
  • 客戶希望統一對待樹中的所有對象。

轉載于:https://www.cnblogs.com/6489c/p/5944066.html

繼續閱讀