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

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

 还是可以的。

原文地址:https://www.cnblogs.com/jsydb/p/12555439.html