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();

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

     还是可以的。

  • 相关阅读:
    UVA 408 (13.07.28)
    linux概念之用户,组及权限
    Java实现 蓝桥杯 历届试题 网络寻路
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 九宫重排
    Java实现 蓝桥杯 历届试题 九宫重排
  • 原文地址:https://www.cnblogs.com/jsydb/p/12555439.html
Copyright © 2011-2022 走看看