命令模式
class AddCommand {
constructor(value) {
this.value = value;
}
execute(state) {
this.redoValue = state;
state = this.value;
return state;
}
undo(state) {
state = this.redoValue;
return state;
}
}
class Manager {
constructor() {
this.state = undefined;
this.commands = [];
this.undoCommands = [];
}
execute(command) {
this.state = command.execute(this.state);
this.commands.push(command);
this.undoCommands = [];
this.log();
}
undo() {
const command = this.commands.pop();
this.state = command.undo(this.state);
this.undoCommands.push(command);
this.log();
}
redo() {
const command = this.undoCommands.pop();
this.state = command.execute();
this.commands.push(command);
this.log();
}
log() {
const manger = new this.constructor();
manger.state = this.state;
manger.commands = this.commands.slice(0);
manger.undoCommands = this.undoCommands.slice(0);
console.log(manger);
}
}
const manger = new Manager();
manger.log(); // => undefined
manger.execute(new AddCommand(1)); // => 1
manger.execute(new AddCommand(2)); // => 2
manger.execute(new AddCommand(3)); // => 3
manger.undo(); // => 2
manger.undo(); // => 1
manger.redo(); // => 2
manger.execute(new AddCommand(4)); // => 4
数据快照
import { createStore } from "redux";
function operationReducer(processor) {
return (state, action) => {
state = { ...state };
// undo、redo 的拦截
if (action.type === "undo") {
state.head = Math.max(0, state.head - 1);
return state;
}
if (action.type === "redo") {
state.head = Math.min(state.timeline.length - 1, state.head + 1);
return state;
}
const { timeline, head, limit } = state;
// operation处理
const snapshot = processor(timeline[head], action);
// timeline处理
if (snapshot !== undefined) {
state.timeline = timeline.slice(0, head + 1);
state.timeline.push(snapshot);
state.timeline = state.timeline.slice(-limit);
state.head = state.timeline.length - 1;
}
return state;
};
}
function processor(state, action) {
if (action.type === "add") {
return action.value;
}
}
const initialManageState = {
timeline: [],
head: -1,
limit: 20
};
const store = createStore(operationReducer(processor), initialManageState);
store.subscribe(() => console.log(store.getState()));
console.log(store.getState()); // => []
store.dispatch({ type: "add", value: 1 }); // => [1]
store.dispatch({ type: "add", value: 2 }); // => [1, 2]
store.dispatch({ type: "add", value: 3 }); // => [1, 2, 3]
store.dispatch({ type: "undo" }); // => [1, 2]
store.dispatch({ type: "undo" }); // => [1]
store.dispatch({ type: "redo" }); // => [1, 2]
store.dispatch({ type: "add", value: 4 }); // => [1, 2, 4]
总结
命令模式代码更加健壮,数据快照代码更加优雅。