zoukankan      html  css  js  c++  java
  • 使用JavaScript浅谈组合模式

    什么是组合模式?

    从前有座山,山上住着一个老和尚和小和尚,老和尚给小和尚讲了一个故事,这个故事是这样子的:从前有座山,山上住着一个老和尚和小和尚,老和尚给小和尚讲了一个故事,这个故事是这样子的:从前有座山,山上住着一个老和尚和小和尚,老和尚给小和尚讲了一个故事,这个故事是这样子的。。。

    骚年,读到这里不知道你明白了什么,一个故事由另一个故事组成,然后一直这样子组合下去,形成了一个最大的故事。

    没错,这就是组合模式:小对象组合成一个大对象,小对象可能由更小的对象组合而成。

    其实我们也可以看出两点:

    1.我们只要最大的对象开始执行相关操作,用户就不需要关心下面的子对象的相关操作(会自动执行)也就是每一个对象要有统一的执行接口(一般就是相同的方法名称)。

    2.这样子一直组合,我们的系统是否能承受的了。(就要对整体进行把握了)。

    我们在电脑中搜索文件的时候,我们有可能搜索的是单个文件,有可能是一个文件夹,也有可能是从一个盘符开始搜索的。其实文件在电脑里面的组合方式,就是典型的组合模式。一个文件夹我们不管里面是有其他文件还是有其他文件,对吧,我们只要在这个文件夹中进行扫描,如果文件存在就一定会存在的。

    我们来看一下代码实现:

    // 定义文件夹
    class Folder {
        constructor(name) {
            this.name = name;
            this.files = [];
        }
        // 添加文件/文件夹
        add(file) {
            this.files.push(file);
        }
        // scan扫描文件
        scan() {
            for (let i = 0, file, files = this.files; file = files[i++];) {
                // 子文件/子文件夹执行扫描
                file.scan();
            }
        }
    }
    // 定义文件
    class File {
        constructor(name) {
            this.name = name;
        }
        scan() {
            console.log('扫描到文件:' + this.name);
        }
    }
    
    var folder = new Folder('最大的文件夹');
    // 向最大的文件夹添加文件
    folder.add(new File('渣女的养成记'));
    folder.add(new File('论如何学会享受孤独'));
    // 新建文件夹
    var folder1 = new Folder('案例集合');
    // 向新文件夹添加文件
    folder1.add(new File('他日若遂凌云志,敢笑黄巢不丈夫'));
    folder1.add(new File('深入浅出学vue'));
    folder1.add(new File('git学习指南'));
    // 把新文件夹加入到最大的文件夹
    folder.add(folder1);
    // 开始扫描
    folder.scan();

    在这里我们定义了文件夹和文件类,注意他们都有一个统一的接口scan,只要执行最大文件夹的scan方法,我们就不需要关心其他子文件夹和子文件的执行,他们会自动执行他们的scan方法,是不是很方便。

    但是我们这里会发现一个问题,那就是file只是一个文件,我们在电脑中向一个文件中添加一个文件是否提示错误的,我们在这里并没有做出控制,如果file执行add操作,那么会报错,这里我们友好的提示一下用户:

    // 定义文件夹
    class Folder {
        constructor(name) {
            this.name = name;
            this.files = [];
        }
        // 添加文件/文件夹
        add(file) {
            this.files.push(file);
        }
        // scan扫描文件
        scan() {
            for (let i = 0, file, files = this.files; file = files[i++];) {
                // 子文件/子文件夹执行扫描
                file.scan();
            }
        }
    }
    // 定义文件
    class File {
        constructor(name) {
            this.name = name;
        }
        scan() {
            console.log('扫描到文件:' + this.name);
        }
        add() {
            throw new Error('文件下面不能再添加文件');
        }
    }
    
    var folder = new Folder('最大的文件夹');
    // 向最大的文件夹添加文件
    folder.add(new File('渣女的养成记'));
    folder.add(new File('论如何学会享受孤独'));
    // 新建文件夹
    var folder1 = new Folder('案例集合');
    // 向新文件夹添加文件
    folder1.add(new File('他日若遂凌云志,敢笑黄巢不丈夫'));
    folder1.add(new File('深入浅出学vue'));
    folder1.add(new File('git学习指南'));
    // 把新文件夹加入到最大的文件夹
    folder.add(folder1);
    // 开始扫描
    folder.scan();
    
    var testFile = new File('测试文件');
    testFile.add(new File('新的文件'));

    现在我们对其做了限制。

    我们设想一下我们有时候是不是会删除文件,删除文件之后,那么之前它的scan方法就不会在执行了。

    但是删除好说,我们要想到这样实现删除了,我们需要怎样删除了。我们的代码中,文件是不是都被保存在文件中,只要找到这个文件夹,我们根据文件名称,是不是就可以执行删除操作了。所以说我们在文件夹执行添加操作的时候,就要把新增文件的所在的文件夹的引用添加到这个文件中。

    我们看一下代码:

    // 定义文件夹
    class Folder {
        constructor(name) {
            this.name = name;
            this.files = [];
        }
        // 添加文件/文件夹
        add(file) {
            this.files.push(file);
            file.parent = this;
        }
        // scan扫描文件
        scan() {
            for (let i = 0, file, files = this.files; file = files[i++];) {
                // 子文件/子文件夹执行扫描
                file.scan();
            }
        }
        remove() {
            if (!this.parent) { //根节点或者树外的游离节点
                return;
            }
            for (let files = this.parent.files, l = files.length; l >= 0; l--) {
                let file = files[l];
                if (this === file) {
                    files.splice(l, 1);
                }
            }
        }
    }
    // 定义文件
    class File {
        constructor(name) {
            this.name = name;
            this.parent = null;
        }
        scan() {
            console.log('扫描到文件:' + this.name);
        }
        add() {
            throw new Error('文件下面不能再添加文件');
        }
        remove() {
            if (!this.parent) { //根节点或者树外的游离节点
                return;
            }
            for (let files = this.parent.files, l = files.length; l >= 0; l--) {
                let file = files[l];
                if (this === file) {
                    files.splice(l, 1);
                }
            }
        }
    }
    
    var folder = new Folder('最大的文件夹');
    // 向最大的文件夹添加文件
    folder.add(new File('渣女的养成记'));
    folder.add(new File('论如何学会享受孤独'));
    // 新建文件夹
    var folder1 = new Folder('案例集合');
    // 向新文件夹添加文件
    folder1.add(new File('他日若遂凌云志,敢笑黄巢不丈夫'));
    folder1.add(new File('深入浅出学vue'));
    folder1.add(new File('git学习指南'));
    // 把新文件夹加入到最大的文件夹
    folder.add(folder1);
    // 开始扫描
    folder.scan();
    
    // 删除文件夹
    console.log('---');
    folder1.remove();
    folder.scan();

    现在我们实现了删除操作,测试如下:

     还是可以的。

  • 相关阅读:
    Arcgis Android 常见问题
    Arcgis Android 手动搭建开发环境
    Arcgis Android 坐标转换
    ArcGis Android 10.2.6更新文档翻译
    arcgis android 中shapefile的加载
    arcgis android 10.2.5开发环境配置
    so far so good
    做什么都要坚持,写blog也一样,
    WPF前台数据验证(红框)Validation.ErrorTemplate 附加属性
    WOSA/XFS及SP综述
  • 原文地址:https://www.cnblogs.com/jsydb/p/12555439.html
Copyright © 2011-2022 走看看