284 lines
7.3 KiB
JavaScript
284 lines
7.3 KiB
JavaScript
/**
|
||
* 基础命令类
|
||
* 所有命令都应该继承这个类
|
||
*/
|
||
export class Command {
|
||
constructor(options = {}) {
|
||
this.name = options.name || "未命名命令";
|
||
this.description = options.description || "";
|
||
this.undoable = options.undoable !== false; // 默认可撤销
|
||
this.timestamp = Date.now();
|
||
}
|
||
|
||
/**
|
||
* 执行命令
|
||
* @returns {*} 执行结果,可以是Promise
|
||
*/
|
||
execute() {
|
||
throw new Error("子类必须实现execute方法");
|
||
}
|
||
|
||
/**
|
||
* 撤销命令
|
||
* @returns {*} 撤销结果,可以是Promise
|
||
*/
|
||
undo() {
|
||
if (!this.undoable) {
|
||
throw new Error("此命令不支持撤销");
|
||
}
|
||
throw new Error("可撤销命令必须实现undo方法");
|
||
}
|
||
|
||
/**
|
||
* 获取命令信息
|
||
*/
|
||
getInfo() {
|
||
return {
|
||
name: this.name,
|
||
description: this.description,
|
||
undoable: this.undoable,
|
||
timestamp: this.timestamp,
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 复合命令类
|
||
* 用于批量执行多个命令,替代事务系统
|
||
*/
|
||
export class CompositeCommand extends Command {
|
||
constructor(commands = [], options = {}) {
|
||
super({
|
||
name: options.name || "复合命令",
|
||
description: options.description || "批量执行多个命令",
|
||
...options,
|
||
});
|
||
|
||
this.commands = Array.isArray(commands) ? commands : [];
|
||
this.executedCommands = []; // 记录已执行的命令,用于撤销
|
||
this.isExecuting = false;
|
||
}
|
||
|
||
/**
|
||
* 添加子命令
|
||
*/
|
||
addCommand(command) {
|
||
if (!command || typeof command.execute !== "function") {
|
||
throw new Error("无效的命令对象");
|
||
}
|
||
this.commands.push(command);
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* 批量添加子命令
|
||
*/
|
||
addCommands(commands) {
|
||
if (Array.isArray(commands)) {
|
||
commands.forEach((cmd) => this.addCommand(cmd));
|
||
}
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* 执行所有子命令(串行执行)
|
||
*/
|
||
async execute() {
|
||
if (this.isExecuting) {
|
||
throw new Error("复合命令正在执行中");
|
||
}
|
||
|
||
this.isExecuting = true;
|
||
this.executedCommands = [];
|
||
|
||
try {
|
||
const results = [];
|
||
|
||
// 串行执行所有子命令
|
||
for (const command of this.commands) {
|
||
try {
|
||
console.log(`📦 复合命令执行子命令: ${command.constructor.name}`);
|
||
|
||
const result = command.execute();
|
||
|
||
// 如果是异步命令,等待完成
|
||
const finalResult = this._isPromise(result) ? await result : result;
|
||
|
||
results.push(finalResult);
|
||
this.executedCommands.push(command);
|
||
|
||
console.log(`✅ 子命令执行成功: ${command.constructor.name}`);
|
||
} catch (error) {
|
||
console.error(`❌ 子命令执行失败: ${command.constructor.name}`, error);
|
||
|
||
// 执行失败时,撤销已执行的命令
|
||
await this._rollbackExecutedCommands();
|
||
throw new Error(`复合命令执行失败:${error.message}`);
|
||
}
|
||
}
|
||
|
||
this.isExecuting = false;
|
||
console.log(`✅ 复合命令执行完成,共执行 ${results.length} 个子命令`);
|
||
return results;
|
||
} catch (error) {
|
||
this.isExecuting = false;
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 撤销所有已执行的子命令(逆序撤销)
|
||
*/
|
||
async undo() {
|
||
if (this.isExecuting) {
|
||
throw new Error("复合命令正在执行中,无法撤销");
|
||
}
|
||
|
||
if (this.executedCommands.length === 0) {
|
||
console.warn("没有已执行的子命令需要撤销");
|
||
return true;
|
||
}
|
||
|
||
console.log(`↩️ 开始撤销复合命令,共 ${this.executedCommands.length} 个子命令`);
|
||
|
||
try {
|
||
// 逆序撤销已执行的命令
|
||
const commands = [...this.executedCommands].reverse();
|
||
const results = [];
|
||
|
||
for (const command of commands) {
|
||
if (typeof command.undo === "function") {
|
||
try {
|
||
console.log(`↩️ 撤销子命令: ${command.constructor.name}`);
|
||
|
||
const result = command.undo();
|
||
|
||
// 如果是异步撤销,等待完成
|
||
const finalResult = this._isPromise(result) ? await result : result;
|
||
|
||
results.push(finalResult);
|
||
console.log(`✅ 子命令撤销成功: ${command.constructor.name}`);
|
||
} catch (error) {
|
||
console.error(`❌ 子命令撤销失败: ${command.constructor.name}`, error);
|
||
// 撤销失败不中断整个撤销过程,但要记录错误
|
||
}
|
||
} else {
|
||
console.warn(`⚠️ 子命令不支持撤销: ${command.constructor.name}`);
|
||
}
|
||
}
|
||
|
||
this.executedCommands = [];
|
||
console.log(`✅ 复合命令撤销完成`);
|
||
return results;
|
||
} catch (error) {
|
||
console.error("❌ 复合命令撤销过程中发生错误:", error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 回滚已执行的命令(内部使用)
|
||
* @private
|
||
*/
|
||
async _rollbackExecutedCommands() {
|
||
console.log(`🔄 开始回滚已执行的 ${this.executedCommands.length} 个子命令`);
|
||
|
||
const commands = [...this.executedCommands].reverse();
|
||
|
||
for (const command of commands) {
|
||
if (typeof command.undo === "function") {
|
||
try {
|
||
console.log(`🔄 回滚子命令: ${command.constructor.name}`);
|
||
const result = command.undo();
|
||
if (this._isPromise(result)) {
|
||
await result;
|
||
}
|
||
console.log(`✅ 子命令回滚成功: ${command.constructor.name}`);
|
||
} catch (error) {
|
||
console.error(`❌ 子命令回滚失败: ${command.constructor.name}`, error);
|
||
// 回滚失败不中断整个回滚过程
|
||
}
|
||
}
|
||
}
|
||
|
||
this.executedCommands = [];
|
||
console.log(`✅ 回滚完成`);
|
||
}
|
||
|
||
/**
|
||
* 检查返回值是否为Promise
|
||
* @private
|
||
*/
|
||
_isPromise(value) {
|
||
return (
|
||
value &&
|
||
typeof value === "object" &&
|
||
typeof value.then === "function" &&
|
||
typeof value.catch === "function"
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 获取复合命令信息
|
||
*/
|
||
getInfo() {
|
||
return {
|
||
...super.getInfo(),
|
||
commandCount: this.commands.length,
|
||
executedCount: this.executedCommands.length,
|
||
isExecuting: this.isExecuting,
|
||
subCommands: this.commands.map((cmd) => (cmd.getInfo ? cmd.getInfo() : cmd.constructor.name)),
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 函数命令包装器
|
||
* 将普通函数包装为命令对象
|
||
*/
|
||
export class FunctionCommand extends Command {
|
||
constructor(executeFn, undoFn = null, options = {}) {
|
||
super({
|
||
name: options.name || "函数命令",
|
||
undoable: typeof undoFn === "function",
|
||
...options,
|
||
});
|
||
|
||
if (typeof executeFn !== "function") {
|
||
throw new Error("执行函数不能为空");
|
||
}
|
||
|
||
this.executeFn = executeFn;
|
||
this.undoFn = undoFn;
|
||
this.executeResult = null; // 保存执行结果用于撤销
|
||
}
|
||
|
||
async execute() {
|
||
const result = this.executeFn();
|
||
this.executeResult = this._isPromise(result) ? await result : result;
|
||
return this.executeResult;
|
||
}
|
||
|
||
async undo() {
|
||
if (!this.undoFn) {
|
||
throw new Error("此函数命令不支持撤销");
|
||
}
|
||
|
||
const result = this.undoFn(this.executeResult);
|
||
return this._isPromise(result) ? await result : result;
|
||
}
|
||
|
||
/**
|
||
* 检查返回值是否为Promise
|
||
* @private
|
||
*/
|
||
_isPromise(value) {
|
||
return (
|
||
value &&
|
||
typeof value === "object" &&
|
||
typeof value.then === "function" &&
|
||
typeof value.catch === "function"
|
||
);
|
||
}
|
||
}
|