1. 什么是“组合模式”?
组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构。
- 用小的子对象构造更大的父对象,而这些子对象也由更小的子对象构成
- 单个对象和组合对象对于用户暴露的接口具有一致性,而同种接口不同表现形式亦体现了多态性
2. 应用场景
组合模式可以在需要针对“树形结构”进行操作的应用中使用,例如扫描文件夹、渲染网站导航结构等等。
3. 代码实现
这里用代码模拟文件扫描功能,封装了File和Folder两个类。在组合模式下,用户可以向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. 参考