首页 > 代码库 > JavaScript设计模式与开发实践---读书笔记(9) 命令模式

JavaScript设计模式与开发实践---读书笔记(9) 命令模式

命令模式的用途:

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

命令模式最常见的应用场景是:有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么。此时希望用一种松耦合的方式来设计程序,使得请求发送者和请求接收者能够消除彼此之间的耦合关系。

命令模式的例子-菜单程序:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>命令模式-菜单程序</title></head><body>    <button id="button1">1</button>    <button id="button2">2</button>    <button id="button3">3</button></body></html><script>    var button1 = document.getElementById(‘button1‘);    var button2 = document.getElementById(‘button2‘);    var button3 = document.getElementById(‘button3‘);    var setCommand = function(button,command){            button.onclick = function(){            command.execute();        }    };    var MenuBar = {        refresh: function(){            console.log(‘刷新菜单目录‘);        },        add: function(){            console.log(‘增加菜单目录‘);        },        del: function(){            console.log(‘删除子菜单‘);        }    };    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(){        console.log(‘删除子菜单‘);    };    var refreshMenuBarCommand = new RefreshMenuBarCommand(MenuBar);    var addSubMenuCommand = new AddSubMenuCommand(SubMenu);    var delSubMenuCommand = new DelSubMenuCommand(SubMenu);    setCommand(button1,refreshMenuBarCommand);    setCommand(button2,addSubMenuCommand);    setCommand(button3,delSubMenuCommand);</script>

以上代码模拟传统面向对象语言的命令模式实现。

命令模式的由来,其实是回调函数的一个面向对象的替代品。

var setCommand = function(button,func){            button.onclick = function(){            func();        }    };    var MenuBar = {        refresh: function(){            console.log(‘刷新菜单目录‘);        }    };//用闭包实现的命令模式如下代码所示:    var RefreshMenuBarCommand = function(receiver){        return function(){            receiver.refresh();        }    };        var refreshMenuBarCommand = new RefreshMenuBarCommand(MenuBar);    setCommand(button1,refreshMenuBarCommand);
//把执行函数改为调用execute方法    var refreshMenuBarCommand = function(receiver){        return{            execute: function(){                receiver.refresh();            }        }    };    var setCommand = function(button,command){        button.onclick = function(){            command.execute();        }    };    var refreshMenuBarCommand = new RefreshMenuBarCommand(MenuBar);    setCommand(button1,refreshMenuBarCommand);

撤销命令:

撤销操作的实现一般是给命令对象增加一个名为unexecute或者undo的方法,在该方法里执行exectue的反向操作。

撤消和重做:

很多时候,我们需要撤销一系列的命令。然而,在某些情况下无法顺利地利用undo操作让对象回到execute之前的状态。

canvas画图中,擦除一条线相对不容易实现。这时候最好的办法是先清除画布,然后把刚才执行过的命令全部重新执行一遍,这一点同样可以利用一个历史列表堆栈办到。记录命令日志,然后重复执行它们,这是逆转不可逆命令的一个好办法。

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>撤销和重做命令</title></head><body>    <button id="replay">播放录像</button></body></html><script>    var Ryu = {        attack: function(){            console.log(‘攻击‘);        },        defense: function(){            console.log(‘防御‘);        },        jump: function(){            console.log(‘跳跃‘);        },        crouch: function(){            console.log(‘蹲下‘);        }    };    var makeCommand = function(receiver,state){        return function(){            receiver[state]();        }    };    var commands = {        "119":"jump",//W        "115":"crouch",//S        "97":"defense",//A        "100":"attack"//D    };    var commandStack = [];    //保存命令的堆栈    document.onkeypress = function(ev){        var keyCode = ev.keyCode,            command = makeCommand(Ryu,commands[keyCode]);        if(command){            command();    //执行命令            commandStack.push(command);//将刚刚执行过的命令保存进堆栈        }    };    document.getElementById(‘replay‘).onclick = function(){    //点击播放录像        var command;        while(command = commandStack.shift()){    //从堆栈里依次取出命令并执行            command();        }    };</script>

命令队列

宏命令:

宏命令是一组命令的集合,通过执行宏命令的方式,可以一次执行一批命令。

    var closeDoorCommand = {        execute: function(){            console.log(‘关门‘);        }    };    var openPcCommand = {        execute: function(){            console.log(‘开电脑‘);        }    };    var openQQCommand = {        execute: function(){            console.log(‘登录QQ‘);        }    };    var MacroCommand = function(){        return {            commandsList:[],            add: function(){                for(var i=0,command;command = this.commandsList[i++]; ){                    command.execute();                }            }        }    };    var macroCommand = MacroCommand();    macroCommand.add(closeDoorCommand);    macroCommand.add(openPcCommand);    macroCommand.add(openQQCommand);    macroCommand.execute();

宏命令是命令模式与组合模式的联用产物。

智能命令与傻瓜命令

命令模式在JavaScript语言中的一种隐形的模式。

JavaScript设计模式与开发实践---读书笔记(9) 命令模式