JavaScript设计模式八(组合模式)

2018-05-02  本文已影响0人  moyi_gg

我们先回顾下上一节中的宏命令。

var closeDoorCommand = {
    execute: function(){
        console.log('close door');
    }
}

var openPCCommand = {
    execute: function() {
        console.log('open pc');
    }
}

var openQQCommand = {
    execute: function() {
        console.log('open qq');
    }
}

var MacroCommand = function() {
    return {
        commandsList: [],
        add: function(command) {
            this.commandsList.push(command);
        },
        execute: function(){
            for(var i = 0; i< this.commandsList.length; i++) {
                this.commandsList[i].execute();
            }
        }
    }
}

var macroCommand = MacroCommand();
macroCommand.add(closeDoorCommand);
macroCommand.add(openPCCommand);
macroCommand.add(openQQCommand);

macroCommand.execute();

其中marcoCommand被称为组合对象,closeDoorCommand、openPcCommand、openQQCommand 都是叶对象。在macroCommand的execute方法里,并不执行真正的操作,而是遍历它所包含的叶对象,把真正的execute请求委托给这些叶对象。

组合模式的定义:

组合模式将对象组合成树形结构,以表示“部分-整体”的层次结构。除了表示树形结构之外,另外一个好处是通过对象的多态性的表现,使得用户对单个对象和组合对象的使用具有一致性

组合模式的用途:

抽象类在组合模式中的作用

我们上面提到组合模式最大的优点在于一致的对待组合对象和基本对象,客户不需要知道当前处理的是宏命令还是普通命令,只要它是个命令,并且有execute方法,这个命令就可以添加到树中。这种透明性在静态语言中显示的更为明显,我们看个例子:

public abstract class Component {
    // add
    public void add (Component child) {};
    // remove 
    public void remove(Component child) {};
}

public class Composite extends Component {
    // add
    public void add (Component child) {};
    // remove 
    public void remove(Component child) {};
}

public class Leaf extends Compnent {
    // add
    public void add (Component child) {
        throw new UnsupportedOperationException() // 叶子节点
    };
    // remove 
    public void remove(Component child) {};
}

public class client () {
    public static void main (String args[]) {
        Component root = new Composite();
        Component c1 = new Composite();
        Component c2 = new Composite();
        Component leaf1 = new Leaf();
        Component leaf2 = new Leaf();
        root.add(c1);
        root.add(c2);
        c1.add(leaf1);
        c2.add(leaf2);
        root.remove();
    }
}

但是JavaScript和Java不一样,编辑器不会去检查类型,所以我们不会弄那么个抽象类,JavaScript中实现组合模式的难点在于保证组合对象和普通对象有相同的方法,这通常需要鸭子类型的思想对其进行接口的检查。

组合模式的例子-扫描文件夹

有没有觉得文件夹和文件之间的关系很方法使用组合模式来描述,看看代码:

// Folder

var Folder = function(name) {
    this.name = name;
    this.files = [];
}

Folder.prototype.add = function(file) {
    this.files.push(file);
}

Folder.prototype.scan = function() {
    for (var i = 0, file, files = this.files; file = files[i++]) {
        file.scan();
    }
}

// File
var File = function(name){
    this.name = name;
}

File.prototype.add = function(file) {
    throw new Error('File can not add');
}

File.prototype.scan = function() {
    console.log('scan ' + this.name);
}

例子:

var folder = new Folder('fe');
var folder1 = new Folder('html');
var folder2 = new Folder('css');
var folder3 = new Folder('js');

var file1 = new File('html权威指南');
var file2 = new File('css权威指南');
var file3 = new File('JavaScript权威指南');

folder1.add(file1);
folder2.add(file2);
folder3.add(file3);
folder.add(folder1);
folder.add(folder2);
folder.add(folder3);

最后如果需要变量,直接调用根节点的folder.scan()就可以啦,哈哈哈

需要注意的地方

上一篇 下一篇

猜你喜欢

热点阅读