首页 > 代码库 > JavaScript设计模式与开发实践---读书笔记(10) 组合模式

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

 

何时使用组合模式:

  • 表示对象的部分-整体层次结构
  • 客户希望统一对待树中的所有对象。

 

JavaScript设计模式与开发实践---读书笔记(10) 组合模式