每天一个设计模式之组合模式

发布时间:2019-09-29 21:56:01编辑:auto阅读(1812)

    作者按:《每天一个设计模式》旨在初步领会设计模式的精髓,目前采用javascriptpython两种语言实现。诚然,每种设计模式都有多种实现方式,但此小册只记录最直截了当的实现方式 :)

    原文地址是:《每天一个设计模式之组合模式》

    欢迎关注个人技术博客:godbmw.com。每周 1 篇原创技术分享!开源教程(webpack、设计模式)、面试刷题(偏前端)、知识整理(每周零碎),欢迎长期关注!

    如果您也想进行知识整理 + 搭建功能完善/设计简约/快速启动的个人博客,请直接戳theme-bmw

    0. 项目地址

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

    组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构。
    1. 用小的子对象构造更大的父对象,而这些子对象也由更小的子对象构成
    2. 单个对象和组合对象对于用户暴露的接口具有一致性,而同种接口不同表现形式亦体现了多态性

    2. 应用场景

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

    3. 代码实现

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

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

    3.1 python3 实现

    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号文件

    3.2 ES6 实现

    // 文件类
    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. 参考

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

关键字