0%

组合模式

组合模式能够给我们提供一个清晰的组成结构,组合对象类通过集成同一个父类使其具有统一的方法,方便我们统一管理和使用。

组合模式用途:

  • 组合模式将对象组合成树形结构,以表示“部分-整体”的层次结构,除了用来表示树形结构外,组合模式可以通过对象的多态性表示,使得用户对单个对象和组合对象的使用具有一致性
  • 请求在树中传递,从树最顶端往下传,如果当前处理请求的对象是叶对象(普通子命令),叶对象会对请求做出相应处理,如果当前处理请求是组合对象,组合对象则会遍历它属下的子节点,将请求继续传递给子节点。

例子

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>

注意:

  1. 组合模式不是父子关系

组合模式是一种HAS-A(聚合)关系,而不是IS-A,组合对象包含一组叶对象,但是leaf不是Composite的子类,组合对象把请求委托给它包含的叶子结点,它们能合作的关键是拥有相同的接口。

  1. 对叶子操作的一致性:

组合模式除了要求组合对象和叶对象拥有相同的接口外,还有一个必要条件,就是对一组叶对象的操作必须具有一致性

  1. 双向映射性:

给父结点和子结点建立双向映射关系,例如给父对象和叶子分别添加集合保存对方的引用,但是,相互之间的引用1过于复杂时会引使得对象之间产生过多耦合性,可以引入中介者模式管理对象

组合模式适用情况:

  • 表示对象的部分-整体层次结构,组合模式可以很方便地构造一棵树来表示对象的部分-整体结构,特别是开发期间不确定这棵树存在多少层次的时候,在树的构造最终完成之后,只需要通过请求树的最顶层对象,就能对树做统一的操作。在组合模式中增加和删除结点很方便,符合“开放-封闭”原则
  • 客户希望统一对待树中所有对象。组合模式可以使客户忽略对象和叶对象的区别,客户在面对这棵树时,不用关心正在处理的对象时组合对象还是叶对象,也就是不用写一堆if,else组合对象和叶对象会各自做正确的事情。