>[success] # 撤销

~~~

1.撤销:撤销操作的实现一般是给命令对象增加一个名为 unexecude 或者 undo 的方法,在该方法里执

行 execute 的反向操作。

2.书中举了一个例子,有一个操作点击后页面中的小球会移动100个像素,为了可以让小球回到初始

的位置,我们可以定义一个方法'unexecude ',这个方法会记录小球移动前的位置,这个方法我们叫它

为'撤销'

~~~
>[danger] ##### 代码
~~~

1.下面是书中代码,通过代码可以发现'MoveCommand' 这个指令对象不像之前我们只提供了一个'execute '

方法,现在我们还提供了一个'undo'方法用来记录小球的初始位置

~~~
~~~
var MoveCommand = function( receiver, pos ){
this.receiver = receiver;
this.pos = pos;
this.oldPos = null;
};
MoveCommand.prototype.execute = function(){
this.receiver.start( 'left', this.pos, 1000, 'strongEaseOut' );
this.oldPos = this.receiver.dom.getBoundingClientRect()[ this.receiver.propertyName ];
// 记录小球开始移动前的位置
};
MoveCommand.prototype.undo = function(){
this.receiver.start( 'left', this.oldPos, 1000, 'strongEaseOut' );
// 回到小球移动前记录的位置
};
~~~
>[success] # 重做
~~~

1.书中说了一些特殊情况的例子:

1.1.我们需要撤销一系列的命令。比如在一个围棋程序中,现在已经下了 10 步棋,我们需要

一次性悔棋到第 5 步。在这之前,我们可以把所有执行过的下棋命令都储存在一个历史列表中,

然后倒序循环来依次执行这些命令的 undo 操作,直到循环执行到第 5 个命令为止

1.2.在一个Canvas 画图的程序中,画布上有一些点,我们在这些点之间画了 N 条曲线把这些

点相互连接起来,当然这是用命令模式来实现的。但是我们却很难为这里的命令对象定义一个擦

除某条曲线的undo 操作,因为在 Canvas 画图中,擦除一条线相对不容易实现。

2.在某些情况下无法顺利地利用 undo 操作让对象回到 execute 之前的状态。这时候最好的办法是先清除,

然后把刚才执行过的命令全部重新执行一遍,这一点同样 可以利用一个历史列表堆栈办到。记录命令日志,

然后重复执行它们,这是逆转不可逆命令的一 个好办法。

~~~
>[danger] ##### 书中的案例
~~~

1.书中的作者做了一个案例,这个案例就是记录你按w s a d,键位,一个按钮点击完后,会重新执行你

刚才的操作,这样就更容易理解了如果遇到'Canvas '这种较为特殊的无法后退的情况,可以通过

'声明一个数组,取值的时候通过堆栈'

2.可以看出在每一次操作的时候都有都会有个一'push数组的操作,用来记录你每次的操作',

在通过'shift()'依次执行

3.通过这案例也拓展了一个思路,如何记录上一次的操作,可以利用数组但数组就不用保存每一步的操作,

个人自己思路数组长度为2固定的,初始的时候数组第一位记录初始化的效果,当数组长度超过二的时候删除

数组中的第一位,这样在push进来的新的让数组长度再次变成2

~~~
~~~

播放录像

var Ryu = {
attack: function(){
console.log( '攻击' );
},
defense: function(){
console.log( '防御' );
},
jump: function(){
console.log( '跳跃' );
},
crouch: function(){
console.log( '蹲下' );
}
};
// ----------------正常思路用法------------------------
// // 需要以此类推写四个命令
// var AttackCommand = function(reciver){
// this.reciver = reciver
// }
// AttackCommand.prototype.execute = function(){
// this.reciver.attack()
// }
// // invoker 调用者
// var setCommand = function(command){
// command.execute()
// }
// --------------------------------------------------
// 利用策略模式配合 解决需要写四个 命令
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();
}
};
~~~