内容简介:组合模式将对象组合成树形结构,以表示“部分-整体”的层次结构。 除了用来表示树形结构之外,组合模式的另一个好处是通过对象的多态性表现,使得用户对单个对象和组合对象的使用具有一致性以命令模式中的宏命令代码为例,宏命令对象包含了一组具体的子命令对象,不管是宏命令对象,还是子命令对象,都有一个execute方法负责执行命令。宏命令中包含了一组子命令,它们组成了一个树形结构,这里是一棵结构非常简单的树在组合模式中,请求在树中传递的过程总是遵循一种逻辑。请求从树最顶端的对象往下传递,如果当前处理请求的对象是叶对象(
组合模式将对象组合成树形结构,以表示“部分-整体”的层次结构。 除了用来表示树形结构之外,组合模式的另一个好处是通过对象的多态性表现,使得用户对单个对象和组合对象的使用具有一致性
以命令模式中的宏命令代码为例,宏命令对象包含了一组具体的子命令对象,不管是宏命令对象,还是子命令对象,都有一个execute方法负责执行命令。宏命令中包含了一组子命令,它们组成了一个树形结构,这里是一棵结构非常简单的树
在组合模式中,请求在树中传递的过程总是遵循一种逻辑。请求从树最顶端的对象往下传递,如果当前处理请求的对象是叶对象(普通子命令),叶对象自身会对请求作出相应的处理;如果当前处理请求的对象是组合对象(宏命令), 组合对象则会遍历它属下的子节点,将请求继续传递给这些子节点。
- 组合模式下的宏命令 目前的万能遥控器,包含了关门、开电脑、登录 QQ 这 3 个命令。现在我们需要一个“超级万能遥控器”,可以控制家里所有的电器,这个遥控器拥有以下功能
- 打开空调
- 打开电视和音响
- 关门、开电脑、登录 QQ
var MacroCommand = function(){ return { commandsList: [], add: function( command ){ this.commandsList.push( command ); }, execute: function(){ for ( var i = 0, command; command = this.commandsList[ i++ ]; ){ command.execute(); } } } }; var openAcCommand = { execute: function(){ console.log( '打开空调' ); } }; /*家里的电视和音响是连接在一起的,所以可以用一个宏命令来组合打开电视和打开音响的命令*/ var openTvCommand = { execute: function(){ console.log( '打开电视' ); } }; var openSoundCommand = { execute: function(){ console.log( '打开音响' ); } }; var macroCommand1 = MacroCommand(); macroCommand1.add(openTvCommand); macroCommand1.add(openSoundCommand); /*关门、打开电脑和打登录 QQ 的命令*/ var closeDoorCommand = { execute: function(){ console.log( '关门' ); } }; var openPcCommand = { execute: function(){ console.log( '开电脑' ); } }; var openQQCommand = { execute: function(){ console.log( '登录 QQ' ); } }; var macroCommand2 = MacroCommand(); macroCommand2.add( closeDoorCommand ); macroCommand2.add( openPcCommand ); macroCommand2.add( openQQCommand ); /*现在把所有的命令组合成一个“超级命令”*/ var macroCommand = MacroCommand(); macroCommand.add( openAcCommand ); macroCommand.add( macroCommand1 ); macroCommand.add( macroCommand2 ); /*最后给遥控器绑定“超级命令”*/ var setCommand = (function( command ){ document.getElementById( 'button' ).onclick = function(){ command.execute(); } })( macroCommand ); 复制代码
从这个例子中可以看到,基本对象可以被组合成更复杂的组合对象,组合对象又可以被组合, 这样不断递归下去,这棵树的结构可以支持任意多的复杂度。在树最终被构造完成之后,让整颗 树最终运转起来的步骤非常简单,只需要调用最上层对象的 execute 方法。每当对最上层的对象 进行一次请求时,实际上是在对整个树进行深度优先的搜索,而创建组合对象的 程序员 并不关心这些内在的细节,往这棵树里面添加一些新的节点对象是非常容易的事情。
应用场景 —— 扫描文件夹
文件夹和文件之间的关系,非常适合用组合模式来描述。文件夹里既可以包含文件,又可以 包含其他文件夹,最终可能组合成一棵树 当使用用杀毒软件扫描该文件夹时,往往不会关心里面有多少文件和子文件夹,组合模式使得我们只需要操作最外层的文件夹进行扫描。
代码实现
/* Folder */ 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++ ]; ){ files file.scan(); } }; /*File*/ var File = function( name ){ this.name = name; }; File.prototype.add = function(){ throw new Error( '文件下面不能再添加文件' ); }; File.prototype.scan = function(){ console.log( '开始扫描文件: ' + this.name ); }; /*创建一些文件夹和文件对象, 并且让它们组合成一棵树,这棵树就是我们 F 盘里的 现有文件目录结构*/ var folder = new Folder( '学习资料' ); var folder1 = new Folder( 'JavaScript' ); var folder2 = new Folder ( 'jQuery' ); var file1 = new File( 'JavaScript 设计模式与开发实践' ); var file2 = new File( '精通 jQuery' ); var file3 = new File('重构与模式' ); folder1.add( file1 ); folder2.add( file2 ); folder.add( folder1 ); folder.add( folder2 ); folder.add( file3 ); /*现在的需求是把移动硬盘里的文件和文件夹都复制到这棵树中,假设我们已经得到了这些文件对象*/ var folder3 = new Folder( 'Nodejs' ); var file4 = new File( '深入浅出 Node.js' ); folder3.add( file4 ); var file5 = new File( 'JavaScript 语言精髓与编程实践' ); /*接下来就是把这些文件都添加到原有的树中*/ folder.add( folder3 ); folder.add( file5 ); 复制代码
小结
组合模式可以让我们使用树形方式创 建对象的结构。我们可以把相同的操作应用在组合对象和单个对象上。在大多数情况下,我们都 可以忽略掉组合对象和单个对象之间的差别,从而用一致的方式来处理它们。 然而,组合模式并不是完美的,它可能会产生一个这样的系统:系统中的每个对象看起来都 与其他对象差不多。它们的区别只有在运行的时候会才会显现出来,这会使代码难以理解。此外,如果通过组合模式创建了太多的对象,那么这些对象可能会让系统负担不起。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 设计模式——订阅模式(观察者模式)
- 设计模式-简单工厂、工厂方法模式、抽象工厂模式
- java23种设计模式-门面模式(外观模式)
- 设计模式-享元设计模式
- Java 设计模式之工厂方法模式与抽象工厂模式
- JAVA设计模式之模板方法模式和建造者模式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。