1. 什么是“组合模式”?

组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构。

  1. 用小的子对象构造更大的父对象,而这些子对象也由更小的子对象构成
  2. 单个对象和组合对象对于用户暴露的接口具有一致性,而同种接口不同表现形式亦体现了多态性

2. 应用场景

组合模式可以在需要针对“树形结构”进行操作的应用中使用,例如扫描文件夹、渲染网站导航结构等等。

3. 代码实现

这里用代码模拟文件扫描功能,封装了FileFolder两个类。在组合模式下,用户可以向Folder类嵌套File或者Folder来模拟真实的“文件目录”的树结构。

同时,两个类都对外提供了scan接口,File下的scan是扫描文件,Folder下的scan是调用子文件夹和子文件的scan方法。整个过程采用的是深度优先

3.1 python3 实现

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
class File:  # 文件类
def __init__(self, name):
self.name = name

def add(self):
raise NotImplementedError()

def scan(self):
print('扫描文件:' + self.name)


class Folder: # 文件夹类
def __init__(self, name):
self.name = name
self.files = []

def add(self, file):
self.files.append(file)

def scan(self):
print('扫描文件夹: ' + self.name)
for item in self.files:
item.scan()


if __name__ == '__main__':

home = Folder("用户根目录")

folder1 = Folder("第一个文件夹")
folder2 = Folder("第二个文件夹")

file1 = File("1号文件")
file2 = File("2号文件")
file3 = File("3号文件")

# 将文件添加到对应文件夹中
folder1.add(file1)

folder2.add(file2)
folder2.add(file3)

# 将文件夹添加到更高级的目录文件夹中
home.add(folder1)
home.add(folder2)

# 扫描目录文件夹
home.scan()

执行$ python main.py, 最终输出结果是:

1
2
3
4
5
6
扫描文件夹: 用户根目录
扫描文件夹: 第一个文件夹
扫描文件:1号文件
扫描文件夹: 第二个文件夹
扫描文件:2号文件
扫描文件:3号文件

3.2 ES6 实现

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
// 文件类
class File {
constructor(name) {
this.name = name || 'File'
}

add() {
throw new Error('文件夹下面不能添加文件')
}

scan() {
console.log('扫描文件: ' + this.name)
}
}

// 文件夹类
class Folder {
constructor(name) {
this.name = name || 'Folder'
this.files = []
}

add(file) {
this.files.push(file)
}

scan() {
console.log('扫描文件夹: ' + this.name)
for (let file of this.files) {
file.scan()
}
}
}

let home = new Folder('用户根目录')

let folder1 = new Folder('第一个文件夹'),
folder2 = new Folder('第二个文件夹')

let file1 = new File('1号文件'),
file2 = new File('2号文件'),
file3 = new File('3号文件')

// 将文件添加到对应文件夹中
folder1.add(file1)

folder2.add(file2)
folder2.add(file3)

// 将文件夹添加到更高级的目录文件夹中
home.add(folder1)
home.add(folder2)

// 扫描目录文件夹
home.scan()

执行$ node main.js,最终输出结果是:

1
2
3
4
5
6
扫描文件夹: 用户根目录
扫描文件夹: 第一个文件夹
扫描文件: 1号文件
扫描文件夹: 第二个文件夹
扫描文件: 2号文件
扫描文件: 3号文件

4. 参考

  • 《JavaScript 设计模式和开发实践》