javaScript设计模式——命令模式(十一)

设计模式:有助于提高代码的复用性和可维护性

假设有一个快餐店,而我是该餐厅店点餐服务员,那么我一天的工作量是这样的:当某位客人点餐或者打来订餐电话的时候,我会把他的需要写在清单上,交给厨房,客人不用关心是哪个厨师给他做饭,我们餐厅还可以满足客人需要定时服务。比如客人可能当前正在回家的路上,要求一个小时后再炒他的菜。只要订单还在,厨师就不会忘记。客人也可以很方便的打电话来撤销他的订单。另外如果有太多的客人点餐,厨房可以按照订单的顺序排队炒菜
这些记录这订单信息的清单,便是命令模式中的命令对象

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

命令模式可以方便的给命令对象添加增加撤销操作,下面看一下这个例子

p标签里面的默认数字是0,可以通过添加按钮,让p标签里的数字递增

<div id="number">0</div>
<button id="add">+</button>
let number = document.getElementById('number')
let worker = {
    //添加
    add(){
        oldValue = isNaN(number.innerHTML)?0:parseInt(number.innerHTML)
        number.innerHTML = oldValue+1
    }
}
//创建添加命令
class AddCommand{
    constructor(receiver){
        this.receiver = receiver
    }
    execute(){
        this.receiver.add()
    }
}
let addCommand = new AddCommand(worker)
    document.getElementById('add').addEventListener('click',function(){
    addCommand.execute()
})

接下来增加撤销按钮

<div id="number">0</div>
<button id="undo">undo</button>

撤销操作一般给命令对象添加一个undo的方法,在数字增加之前,先记录当前的数字,在执行undo方法的时候,再让数字回到之前

let worker = {
    oldValue:0,
    //添加
    add(){
        oldValue = isNaN(number.innerHTML)?0:parseInt(number.innerHTML)
        worker.oldValue = oldValue //记录之前的数字
        number.innerHTML = oldValue+1
    },
    //撤销
    undo(){
        number.innerHTML = worker.oldValue
    }
}
//创建撤销命令
class UndoCommand{
    constructor(receiver){
        this.receiver = receiver
    }
    execute(){
        this.receiver.undo()
    }
}
let undoCommand = new UndoCommand(worker)
document.getElementById('undo').addEventListener('click',function(){
    undoCommand.execute()
})

现在通过命令模式轻松的实现来撤销功能。如果用普通的方法来调用,也许每次都要记录数字,才能让它返回之前都数字。而命令模式中之前都数字已经作为command对象都属性保存起来来,所以只需要提供一个undo方法,并且在undo方法中让数字回到之前到就可以了

上面的撤销只可以撤销一步,很多时候,我们需要撤销一系列的命令。比如浏览器的前进和回退按钮。这样的话,我们把所以执行的命令都存到一个history列表中,切换对应都索引值,来拿到当前都数据,请看下列代码实现

<button id="redo">redo</button>
let number = document.getElementById('number')
let worker = {
    history:[],
    index:-1,
    //添加
    add(){
        var oldValue = isNaN(number.innerHTML)?0:parseInt(number.innerHTML)
        var newValue = oldValue+1
        worker.history.push(newValue)
        worker.index = worker.history.length - 1;
        number.innerHTML = oldValue+1
    },
    //撤销
    undo(){
        if(worker.index>0){
            worker.index--;
            number.innerHTML = worker.history[worker.index]
        }
    },
    //重做
    redo(){
        if(worker.history.length-1>worker.index){
            worker.index++;
            number.innerHTML = worker.history[worker.index]
        }
    }
}
//创建命令
class RedoCommand{
    constructor(receiver){
        this.receiver = receiver
    }
    execute(){
        this.receiver.redo()
    }
}

let redoCommand = new RedoCommand(worker)
document.getElementById('redo').addEventListener('click',function(){
    redoCommand.execute()
})

然而,有时候我们无法顺利都利用redo回到之前都execute之前都状态,比如在Canvas画图都过程中,画布上都每一点,我们这些点之间画来n条曲线连接起来,当然这是用命令模式实现都。但是我们却很难为这里都命令对象定义一个擦除某条曲线都undo操作,因为在Canvas画图中,擦除一条线相对不容易实现
这时候最好都办法是先清除画布,然后把刚才执行多都命令全部中心执行一遍,者一点同样利用一个历史列表堆栈办到。记录命令日志,然后重复执行他们,这是是逆转不可逆命令都一个好办法

常用的12种设计模式
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值