组合模式就是用小的子对象来构建更大的对象,这些小的子对象也许是由更小的‘‘孙对象’构成的。
marcoCommand 被称为组合对象,closeDoorCommand、openPcCommand、openQQCommand 都是
叶对象。
例如 :目前的万能遥控器,包含了关门、开电脑、登录 QQ 这 3 个命令。现在我们需要一个“超级
万能遥控器”,可以控制家里所有的电器,这个遥控器拥有以下功能:
打开空调
打开电视和音响
关门、开电脑、登录 QQ
首先再节点中放置一个按钮button来表示这个超级万能遥控器,遥控器上安装了宏命令,当执行这个宏命令时会依次执行它所有包含的子命令。
<button id="button">按我</button>
//js
//定义宏命令
var MacroCommand = function(){
return{
commandsList:[],
add:function(command){
this.commandsList.push(command) ;
},
execute:function(){
for(var i = 0,command;command = this.commandList[i++]){
command.excute();
}
}
}
}
// 定义 叶对象(子命令)
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 );
当按下遥控器的按钮时,所有命令都将被依次执行
从这个例子中可以看到,基本对象可以被组合成更复杂的组合对象,组合对象又可以被组合,
这样不断递归下去,这棵树的结构可以支持任意多的复杂度。
组合模式最大的优点在于可以一致地对待组合对象和基本对象
组合对象可以拥有子节点,叶对象下面就没有子节点, 所以我们也许会发生一些误操作,
比如试图往叶对象中添加子节点。解决方案通常是给叶对象也增加 add 方法,并且在调用这个方
法时,抛出一个异常来及时提醒客户,代码如下:
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 openTvCommand = {
execute: function(){
console.log( '打开电视' );
},
add: function(){
throw new Error( '叶对象不能添加子节点' );
}
};
var macroCommand = MacroCommand();
macroCommand.add( openTvCommand );
openTvCommand.add( macroCommand ) // Uncaught Error: 叶对象不能添加子节点