JavaScript设计模式七(命令模式)

JavaScript设计模式七(命令模式)

定义:

命令模式是最简单和优雅的模式之一,命令模式中的命令指的是一个执行某些特定事情的指令

使用场景:
有时候需要向某些对象发送请求,但是不知道请求的接受者是谁,也不知道被请求的操作是什么。这种情况需要我们设计发送者和请求的接受者消除彼此的耦合关系。

命令模式的例子

假设我们在编写一个程序,用户界面上至少由数十按钮,因为项目负责,我们让两个程序员参与,一个写样式,一个写点击按钮后的行为,这些行为都封装在对象里面。这里对于绘制按钮的程序员来说,他根本就不知道某个按钮的作用,他只知道这些按钮会被点击,然后触发一些事情。所以这个就很适合用命令模式来把按钮和具体行为解耦合。

<body>
    <button id="btn1">button1</button>
    <button id="btn2">button2</button>
    <button id="btn3">button3</button>
</body>
<script>
    var btn1 = document.getElementById('btn1');
    var btn2 = document.getElementById('btn2');
    var btn3 = document.getElementById('btn3');
</script>

我们上面说了,这些按钮肯定会执行一些操作,我们叫command,执行的动作我们约定调用command对象的execute方法,虽然我们不知道这些命令代表的是啥子,但是负责绘制按钮的程序员也不关心这些,只需要预留好安装命令的接口,command对象自然就知道如何正确的沟通

var setCommand = function(button, command) {
    button.onclick = function() {
        command.execute();
    };
};

然后我们在看那个写交互button的程序员,他写了刷新界面、增加子菜单和删除子菜单这几个功能

var MenuBar = {
    refresh: function() {
        conosle.log('refresh');
    },
};

var SubMenu = {
    add: function() {
        console.log('add');
    },
    del: function() {
        console.log('del');
    }
}

为了让button变得有用,我们需要把这行行为都封装到命令类里面去。

var RefreshMenuBarCommand = function(receiver) {
    this.receiver = receiver;
}

RefreshMenuBarCommand.prototype.execute = function() {
    this.receiver.refresh();
}

var AddSubMenuCommand = function(receiver) {
    this.receiver = receiver;
}

AddSubMenuCommand.prototype.execute = function() {
    this.receiver.add();
}

var DelSubMenuCommand = function(receiver) {
    this.receiver = receiver;
}

DelSubMenuCommand.prototype.execute = function(){
    this.receiver.del();
}

使用方法:

var refreshMenuBarCommand = new RefreshMenuBarCommand(MenuBar);
var addSubMenuCommand = new AddSubMenuCommand(SubMenu);
var delSubMenuCommand = new DelSubMenuCommand(SubMenu);

setCommand( btn1, refreshMenuBarCommand );
setCommand( btn2, addSubMenuCommand );
setCommand( btn3, delSubMenuCommand );

这样子做我们可以看到请求的发送者和请求的接受者是耦合开的。可以随意改变,随意组合

JavaScript中的命令模式

我不知道大家看了上面的代码怎么想的,我感觉很奇怪,至少我们实际中不会这么写代码。我们的目的是给对象去了一个execute的方法,为了达到这个目的,我们引入了command对象和receiver两个角色。

var bindClick = function(button, func) {
    button.click = func;
}
var MenuBar = {
    refresh: function() {
        conosle.log('refresh');
    },
};

var SubMenu = {
    add: function() {
        console.log('add');
    },
    del: function() {
        console.log('del');
    }
}
bindClick(btn1, MenuBar.refresh);
bindClick(btn2, SubMenu.add);
bindClick(btn3, SubMenu.del);

上一节中的实现方式是模拟的面向对象的方式来实现的,命令模式把过程化的请求封装到了command对象的execute方法中,通过封装来把运算包装。
命令模式的由来其实是回调函数面向对象的一个替代品。
JavaScript作为函数式语言,和策略模式一样,命令模式早就融入到了JavaScript中,运算块不一定要封装到command对象中,封装到函数中也是也可以的,因为函数可以作为参数到处传递,接下来我们看如何利用闭包来实现命令模式

var setCommand = function(button, func) {
    button.onclick = function() {
        func();
    };
};

var MenuBar = {
    refresh: function() {
        conosle.log('refresh');
    },
};

var RefreshMenuBarCommand = function(receiver) {
    return function() {
        receiver.refresh();
    }
}

var refershMenuBarCommand = RefreshMenuBarCommand(MenuBar);
setCommand(btn1, refershMenuBarCommand)

命令模式除了执行命令外,还是撤销命令、重做命令等等,所以我们把上面的代码稍微修改下

var setCommand = function(button, command) {
    button.onclick = function() {
        command.execute();
    };
};

var RefreshMenuBarCommand = function(receiver) {
    return {
        execute: function() {
            receiver.refresh();
        }
    }
}

var refershMenuBarCommand = RefreshMenuBarCommand(MenuBar);
setCommand(btn1, refershMenuBarCommand);

至于撤销和重做是类似的

宏命令

宏命令是指一组命令,通过宏命令,我们执行一批命令,例如我们需要点击一下app,自动把门关上,顺便打开电脑,登录QQ

我们第一步,当然是创建这一个个命令拉

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

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

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

然后定义下宏命令,增加一个add方法把子命令添加进去,调用宏命令的execute方法时,会迭代刚才添加的子命令,并以此执行

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

猜你喜欢

转载自blog.csdn.net/lihangxiaoji/article/details/80005804