美文网首页
7.设计模式(命令模式)

7.设计模式(命令模式)

作者: 悠哈121 | 来源:发表于2020-11-10 17:28 被阅读0次

    1.命令模式最常见的应用场景:有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么,此时希望用一种松耦合的方式来设计程序,使得请求发送这和请求接收者能够消除彼此之间的耦合关系
    举例:订餐,客人需要像厨师发送请求,但是完全不知道这些厨师的名字和联系方式,也不知道厨师的炒菜方式和步骤。命令模式把客人的请求封装成command对象,也就是订餐中的订单对象。这个对象可以在程序中被四处传递,就像订单可以从服务员手中传到厨师的手中,这样一来客人不需要知道厨师的名字,从而解开了请求调用者和请求接收者之间的耦合关系

    代码实现(1.假设我们正在编写用户界面程序,一个程序员负责绘制按钮,而另外一些程序员则负责编写点击按钮后的具体行为,这些行为都被封装在对象里,那么当绘制完按钮,如何给它绑定事件呢)
    <button id="btn">点击按钮</button>
    <script>
     var btn = document.getElementById( 'btn' );
     {/* setCommand函数负责在按钮上面安装命令。可以肯定的是点击按钮会执行某个command命令,执行命令的动作被约定为调用command对象的execute方法 */}
     var setCommand = function (btn,command) {
       btn.onclick = function() {
         command.execute()
       }
     }
     {/* 编写点击按钮之后的具体行为 */}
     var menuBar = {
       refresh:function() {
        console.log( '刷新菜单目录' );
       }
     }
     var refreshMenuBarCommand= function(receiver) {
       this.receiver = receiver
     }
     refreshMenuBarCommand.prototype.excute = function(){
       this.receiver.refresh()
     }
    var refreshMenuBarCommand = new refreshMenuBarCommand( menuBar );
    setCommand( btn, refreshMenuBarCommand );
    //我们会感动奇怪,引入command和receiver这两个把简单的事情复杂化了
    var bindClick = function(btn,fn){
      btn.onClick = fn
    }
    var menuBar = {
      refresh:function(){
        console.log("xxxx")
      }
    }
    bindClick(btn,menuBar.refresh)
    //这种说法是正确的,在传统面向对象语言的命令模式实现中,命令模式将过程式的请求调用封装在command对象的execute中,命令的接收者被当成command对象的属性保存起来,同时约定执行命令的操作调用command.execute方法
    代码实现(2.撤销命令,撤销是命令模式里一个非常有用的功能,试想一下开发围棋程序的时候,我们把每一步棋子的变化都封装成命令,则可以轻而易举地实现悔棋功能。同样还可以实现文本编辑器的crtl+z功能)
    //现在页面有一个input文本框和一两个button按钮,文本框中可以输入一些数字,表示小球移动后的水平位置,小球在用户点击按钮后开始移动,然后还有一个取消按钮,小球回到移动之前的位置,当然我们可以在文本框中输入负值,点击移动按钮,我们将使用命令模式实现这两个功能
     <div id="ball" style="position:absolute;background:#000;width:50px;height:50px"></div> 
     输入小球移动后的位置:<input id="pos"/> 
     <button id="moveBtn">开始移动</button> 
     <button id="cancelBtn">开始移动</button> 
    </body> 
    <script> 
     var ball = document.getElementById( 'ball' ); 
     var pos = document.getElementById( 'pos' ); 
     var moveBtn = document.getElementById( 'moveBtn' ); 
     var cancelBtn = document.getElementById( 'cancelBtn' ); 
     var setCommand = function(receiver,position) {
      this.receiver = receiver;
      this.position = position;
    }
    setCommand.prototype.execute = function(pos) {
      this.oldValue = -pos.value;
      this.receiver.start('left', pos.value, 1000, 'strongEaseOut' )
    }
    setCommand.prototype.undo = function() {
      this.receiver.start('left', this.oldValue, 1000, 'strongEaseOut' )
    }
    var SetCommand;
    moveBtn.onclick = function(){ 
        var animate = new Animate( ball ); 
        SetCommand = new setCommand(animate,pos);
        SetCommand.execute()
     }; 
    cancelBtn.onclick = function(){ 
        SetCommand.undo()
     }; 
    代码实现(3.重做,播放录像:我们把用户在键盘的输入都封装成命令,执行过的命令放到堆栈中,播放录像的时候只需要从头开始依次执行这些命令便可)
    var Ryu = {
      attack:function() {
        console.log("防御")
      },
      defense:function(){
        console.log("攻击")
      },
      jump:function() {
        console.log("跳跃")
      },
      crouch:function(){
        console.log("蹲下")
      }
    }
    //模拟键盘
    var A = { key:'attack'},W = { key:'defense'},D = { key:'jump'},S ={ key:'crouch'};
    var setCommand = function(receiver,key) {
      this.receiver = receiver;
      this.key = key.key;
    }
    setCommand.prototype.excute = function() {
      let _this = this;
      return function () {
        _this.receiver[_this.key]()
      }
    }
    // 模拟按下a w s d
    let a = [A,W,S,D];
    let commandStack = [];
    for(let i = 0; i < 4; i++){
     var command = new setCommand(Ryu,a[i]);
     let fn = command.excute();
     fn();
     commandStack.push(fn)
    }
    //模拟重新播放按钮
    commandStack.forEach(fn=>fn())
    </script>
    

    js可以用高阶函数非常方便的实现命令模式,命令模式在js中是一种隐形的模式

    相关文章

      网友评论

          本文标题:7.设计模式(命令模式)

          本文链接:https://www.haomeiwen.com/subject/gohjbktx.html