组合模式能够给我们提供一个清晰的组成结构,组合对象类通过集成同一个父类使其具有统一的方法,方便我们统一管理和使用。
组合模式用途:
- 组合模式将对象组合成树形结构,以表示“部分-整体”的层次结构,除了用来表示树形结构外,组合模式可以通过对象的多态性表示,使得用户对单个对象和组合对象的使用具有一致性
- 请求在树中传递,从树最顶端往下传,如果当前处理请求的对象是叶对象(普通子命令),叶对象会对请求做出相应处理,如果当前处理请求是组合对象,组合对象则会遍历它属下的子节点,将请求继续传递给子节点。
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| <body> <button id="button">按我</button> <script> let MacroCammond = function(){ return{ commandList:[], add: function(command){ this.commandList.push(command) }, execute: function(){ for(let i = 0,command;command = this.commandList[i++];){ command.execute() } } } }; let openAcCommand = { execute: function(){ console.log('打开空调') } } let openTvCommand = { execute: function(){ console.log('打开电视') } } let macroCommand1 = MacroCammond() macroCommand1.add(openAcCommand) macroCommand1.add(openTvCommand) let closeDoorCommand = { execute:function(){ console.log('关门') } } let openComputer = { execute: function(){ console.log('开电脑') } } let macroCommand2 = MacroCammond() macroCommand2.add(closeDoorCommand) macroCommand2.add(openComputer) let macroCommand = MacroCammond() macroCommand.add(macroCommand1) macroCommand.add(macroCommand2) let setCommand = (function(command){ document.getElementById('button').onclick = function(){ command.execute() } })(macroCommand)
</script> </body>
|
注意:
- 组合模式不是父子关系
组合模式是一种HAS-A(聚合)关系,而不是IS-A,组合对象包含一组叶对象,但是leaf不是Composite的子类,组合对象把请求委托给它包含的叶子结点,它们能合作的关键是拥有相同的接口。
- 对叶子操作的一致性:
组合模式除了要求组合对象和叶对象拥有相同的接口外,还有一个必要条件,就是对一组叶对象的操作必须具有一致性
- 双向映射性:
给父结点和子结点建立双向映射关系,例如给父对象和叶子分别添加集合保存对方的引用,但是,相互之间的引用1过于复杂时会引使得对象之间产生过多耦合性,可以引入中介者模式管理对象
组合模式适用情况:
- 表示对象的部分-整体层次结构,组合模式可以很方便地构造一棵树来表示对象的部分-整体结构,特别是开发期间不确定这棵树存在多少层次的时候,在树的构造最终完成之后,只需要通过请求树的最顶层对象,就能对树做统一的操作。在组合模式中增加和删除结点很方便,符合“开放-封闭”原则
- 客户希望统一对待树中所有对象。组合模式可以使客户忽略对象和叶对象的区别,客户在面对这棵树时,不用关心正在处理的对象时组合对象还是叶对象,也就是不用写一堆if,else组合对象和叶对象会各自做正确的事情。