基础知识

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > 基础知识 > javascript命令模式

javascript设计模式之命令模式

作者:石头山_S

这篇文章主要为大家介绍了javascript命令模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

一. 认识命令模式

所谓命令,也就是指执行某些特定事情的指令,就拿喝水的例子来说,喝水执行的指令就是将水倒在杯子里,然后端起杯子送入口中,这就是一条命令,无论谁喝水都是这个步骤,我们不关心是谁端起了杯子,也不关心杯子中的水到底是水还是其他东西。我们只关心这个过程,将水倒在杯子中,然后端起杯子送入口中,最后谁喝掉了,喝掉的是饮料还是水不重要。

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

二. 代码实现-实际应用场景

在实际开发中团队协作是最重要的环节,假如两个人分别得到两个不同的任务,一个人负责页面中所有的 button 按钮的美化,另一个人负责实现这些 button 的逻辑,我们在写 button 逻辑时不知道该 button 最终绑定的是页面中的哪一个按钮,也不知道具体点击该按钮会发生什么,此时我们用命令模式来设计,来解开按钮和负责具体行为对象间的耦合,代码如下所示。

    <script>
        let btns = document.querySelectorAll('button');
        // 写一个刷新命令
        let refreshCommand = {
            execute () {
                console.log("刷新页面");
            }
        }
        // 写一个登录按钮命令
        let loginCommand = {
            execute () {
                console.log("执行登录操作");
            }
        }
        let setCommand = function( button, command) {
            button.onclick = function() {
                command.execute();
            }
        }
        // 假如第三个按钮用来负责刷新页面,第五个用来负责登录操作
        setCommand( btns[2], refreshCommand);
        setCommand( btns[4], loginCommand);  

分析:我们将点击按钮后可能会发生的事件分别封装起来,它们中各自有自己的 execute 函数,我们将安装按钮功能的函数封装到了 setCommand 中,最后根据需求对应安装各个按钮的功能便可。

三. 命令模式的撤销操作

下达一个命令后,我们可能不需要了,想回到下达命令之前的状态,就需要用到撤销操作,撤销操作的实现一般是给命令对象增加一个 undo 或者 unexecute 方法,在其中执行 execute 的反向操作。

// 假如写一个人物向左移的命令
let moveLeftCommand = {
    execute() {
        console.log("人物向左移动");
}
    undo (){
        console.log("人物向又移动");
}
}

这种是简单的逻辑实现,假如有些撤销行为无法用执行他的反向操作来实现,那我们应该怎么办呢?

带着这个问题我们学习一种新的达到撤销的方式,我们用一个栈来记录每一步命令,想要撤销,我们只需要重头开始,从栈中拿出命令来分别执行,将最后一次命令删除即可。如果不删除最后一次命令依次执行,我们又实现了一个新的功能,重播。

这是一个通过 WASD 来控制小球移动的代码实现,我们每次按下一个有效命令时,便会将该命令推入 commandStack 中来记录小球的变化,当点击重播时小球会按照之前同样的轨迹运动。

        let role = document.getElementById('role');
        
        let move = {
            dom: role,
            leftt:0,
            top: 0,
            up() {
                console.log("向上");
                this.top -= 10;
                this.dom.style.top = this.top + 'px';
            },
            down(){
                console.log("向下");
                this.top += 10;
                this.dom.style.top = this.top + 'px';
            },
            left() {
                console.log("向左");
                this.leftt -= 10;
                this.dom.style.left = this.leftt + 'px';
            },
            right() {
                console.log("向右");
                this.leftt += 10;
                this.dom.style.left = this.leftt + 'px';
            }
        }
        commands = {
            "119": "up",      // W
            "115": "down",    // S
            "97": "left",    // A
            "100": "right"     // D
        };
        commandStack = []; // 保存命令的堆栈
        let setCommand = function (receiver, state) {
            return function() {
                receiver[state]();
            }
        }
        document.addEventListener('keypress', (e) => {
            let code = e.charCode;
            if(!commands[code]) {
                return ;
            }
            let command = setCommand(move, commands[code]);
            if( command ) {
                command();
                commandStack.push( command );
            }
        })
        // 设置重播按钮
        document.getElementById('replay').onclick = function() {
            let command;
            while(command = commandStack.shift()) {
                command();
            }
        }

四. 宏命令

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

通俗来说就是,有一件事你需要重复做,并且做这件事的每一步都是固定不变的,那么我们可以将做这件事情的所有步骤打包起来,只需要启动,便可以自动完成所有步骤。

需求:实现一个游戏自动刷副本的脚本

​        let MacroCommand = function() {
            return {
                commandList: [],
                add( command ) {
                    this.commandList.push(command);
                },
                execute () {
                    for(let i = 0,command; command = this.commandList[i++];){
                        command.execute();
                    }
                }
            }
        }
        let startGameCommand = {
            execute() {
                console.log('开始游戏')
            }
        }
        let killGhostCommand = {
            execute() {
                console.log('打怪')
            }
        }
        let giftCommand = {
            execute() {
                console.log("领取奖励")
            }
        }
        let outGameCommand = {
            execute() {
                console.log("退出游戏")
            }
        }
        let Game = MacroCommand();
        Game.add(startGameCommand);
        Game.add(killGhostCommand);
        Game.add(giftCommand);
        Game.add(outGameCommand);
        Game.execute();  

我们只需要为宏命令对列中添加命令,它会自动执行里边的所有命令。我们只负责启动,其他的就不需要我们管了,我们可以放心的去做其他事情,等待它自己完成。

五. 总结

命令模式中也提到了傻瓜命令智能命令,它两的区别在于傻瓜命令中含有命令的接收者,而智能命令没有,它直接提供请求。智能命令与策略模式十分相近,只是在使用上不同,策略模式中对象的目标相同,只是实现目标的算法不同,而命令模式的目标更具有散发性。命令模式还可以完成撤销、排队的功能。

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

您可能感兴趣的文章:
阅读全文