当前位置: 首页 > news >正文

设计模式- 命令模式详解

命令模式详解

目录

  1. 命令模式简介
  2. 核心流程
  3. 重难点分析
  4. Spring中的源码分析
  5. 具体使用场景
  6. 面试高频点

命令模式简介

定义

命令模式(Command Pattern)是一种行为型设计模式,它将请求封装成一个对象,从而让你可以用不同的请求、队列或日志来参数化其他对象。命令模式也支持可撤销的操作。

核心思想

  • 封装请求:将请求封装成对象,使请求参数化
  • 解耦调用者和接收者:调用者不需要知道具体的接收者
  • 支持撤销和重做:可以记录命令历史,实现撤销功能
  • 支持宏命令:可以将多个命令组合成一个复合命令

模式结构

  • Command(命令接口):声明执行操作的接口
  • ConcreteCommand(具体命令):实现命令接口,绑定接收者
  • Invoker(调用者):调用命令对象执行请求
  • Receiver(接收者):知道如何执行与请求相关的操作
  • Client(客户端):创建具体命令对象并设置接收者

核心流程

命令模式流程图

接收者
调用者
命令对象
业务对象A
业务对象B
业务对象C
命令队列
执行方法
撤销方法
命令接口
具体命令A
具体命令B
宏命令
客户端
创建具体命令
设置接收者
设置调用者
调用者执行命令
命令调用接收者方法
接收者执行具体操作
返回执行结果

基本实现流程

1. 定义命令接口
public interface Command {void execute();void undo();
}
2. 定义接收者
public class Light {private boolean isOn = false;public void turnOn() {isOn = true;System.out.println("灯已打开");}public void turnOff() {isOn = false;System.out.println("灯已关闭");}public boolean isOn() {return isOn;}
}
3. 实现具体命令
public class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOn();}@Overridepublic void undo() {light.turnOff();}
}public class LightOffCommand implements Command {private Light light;public LightOffCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOff();}@Overridepublic void undo() {light.turnOn();}
}
4. 定义调用者
public class RemoteControl {private Command[] onCommands;private Command[] offCommands;private Command undoCommand;public RemoteControl() {onCommands = new Command[7];offCommands = new Command[7];undoCommand = new NoCommand();}public void setCommand(int slot, Command onCommand, Command offCommand) {onCommands[slot] = onCommand;offCommands[slot] = offCommand;}public void onButtonWasPushed(int slot) {if (onCommands[slot] != null) {onCommands[slot].execute();undoCommand = onCommands[slot];}}public void offButtonWasPushed(int slot) {if (offCommands[slot] != null) {offCommands[slot].execute();undoCommand = offCommands[slot];}}public void undoButtonWasPushed() {undoCommand.undo();}
}
5. 客户端使用
public class Client {public static void main(String[] args) {// 创建接收者Light light = new Light();// 创建命令Command lightOn = new LightOnCommand(light);Command lightOff = new LightOffCommand(light);// 创建调用者RemoteControl remote = new RemoteControl();remote.setCommand(0, lightOn, lightOff);// 执行命令remote.onButtonWasPushed(0);remote.offButtonWasPushed(0);remote.undoButtonWasPushed();}
}

重难点分析

重难点1:命令的撤销和重做

问题描述

实现命令的撤销和重做功能需要考虑状态管理和历史记录。

解决方案
public class CommandHistory {private Stack<Command> history = new Stack<>();private Stack<Command> redoHistory = new Stack<>();public void executeCommand(Command command) {command.execute();history.push(command);redoHistory.clear(); // 清空重做历史}public void undo() {if (!history.isEmpty()) {Command command = history.pop();command.undo();redoHistory.push(command);}}public void redo() {if (!redoHistory.isEmpty()) {Command command = redoHistory.pop();command.execute();history.push(command);}}
}// 支持状态保存的命令
public class LightOnCommand implements Command {private Light light;private boolean previousState;public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {previousState = light.isOn();light.turnOn();}@Overridepublic void undo() {if (previousState) {light.turnOn();} else {light.turnOff();}}
}

重难点2:宏命令的实现

问题描述

如何将多个命令组合成一个复合命令。

解决方案
public class MacroCommand implements Command {private List<Command> commands;public MacroCommand(List<Command> commands) {this.commands = commands;}@Overridepublic void execute() {for (Command command : commands) {command.execute();}}@Overridepublic void undo() {// 逆序执行撤销for (int i = commands.size() - 1; i >= 0; i--) {commands.get(i).undo();}}
}// 使用宏命令
public class PartyMode {public static void main(String[] args) {Light light = new Light();TV tv = new TV();Stereo stereo = new Stereo();List<Command> partyCommands = Arrays.asList(new LightOnCommand(light),new TVOnCommand(tv),new StereoOnCommand(stereo));Command partyMode = new MacroCommand(partyCommands);RemoteControl remote = new RemoteControl();remote.setCommand(0, partyMode, new NoCommand());remote.onButtonWasPushed(0); // 执行所有命令}
}

重难点3:命令队列和异步执行

问题描述

如何实现命令的队列管理和异步执行。

解决方案
public class CommandQueue {private Queue<Command> queue = new LinkedList<>();private ExecutorService executor = Executors.newFixedThreadPool(5);private volatile boolean running = true;public void addCommand(Command command) {synchronized (queue) {queue.offer(command);queue.notify();}}public void start() {executor.submit(() -> {while (running) {Command command = null;synchronized (queue) {while (queue.isEmpty() && running) {try {queue.wait();} catch (InterruptedException e) {Thread.currentThread().interrupt();return;}}if (running) {command = queue.poll();}}if (command != null) {try {command.execute();} catch (Exception e) {System.err.println("命令执行失败: " + e.getMessage());}}}});}public void stop() {running = false;synchronized (queue) {queue.notifyAll();}executor.shutdown();}
}

重难点4:命令的持久化和恢复

问题描述

如何将命令持久化到文件或数据库,并在系统重启后恢复。

解决方案
public interface SerializableCommand extends Command, Serializable {String getCommandType();Map<String, Object> getParameters();
}public class LightOnCommand implements SerializableCommand {private String lightId;private transient Light light; // 不序列化public LightOnCommand(String lightId) {this.lightId = lightId;}@Overridepublic void execute() {if (light == null) {light = LightManager.getInstance().getLight(lightId);}light.turnOn();}@Overridepublic String getCommandType() {return "LIGHT_ON";}@Overridepublic Map<String, Object> getParameters() {Map<String, Object> params = new HashMap<>();params.put("lightId", lightId);return params;}
}public class CommandPersistence {private static final String COMMAND_FILE = "commands.ser";public void saveCommands(List<SerializableCommand> commands) {try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(COMMAND_FILE))) {oos.writeObject(commands);} catch (IOException e) {System.err.println("保存命令失败: " + e.getMessage());}}@SuppressWarnings("unchecked")public List<SerializableCommand> loadCommands() {try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(COMMAND_FILE))) {return (List<SerializableCommand>) ois.readObject();} catch (IOException | ClassNotFoundException e) {System.err.println("加载命令失败: " + e.getMessage());return new ArrayList<>();}}
}

Spring中的源码分析

CommandLineRunner接口

@FunctionalInterface
public interface CommandLineRunner {void run(String... args) throws Exception;
}// 使用示例
@Component
public class DatabaseInitializer implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {System.out.println("初始化数据库...");// 初始化逻辑}
}

ApplicationRunner接口

@FunctionalInterface
public interface ApplicationRunner {void run(ApplicationArguments args) throws Exception;
}// 使用示例
@Component
public class ConfigLoader implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {System.out.println("加载配置...");// 配置加载逻辑}
}

Spring Boot中的命令模式应用

// 自定义命令接口
public interface TaskCommand {void execute();void undo();String getDescription();
}// 具体命令实现
@Component
public class DatabaseBackupCommand implements TaskCommand {@Autowiredprivate DatabaseService databaseService;@Overridepublic void execute() {System.out.println("开始数据库备份...");databaseService.backup();System.out.println("数据库备份完成");}@Overridepublic void undo() {System.out.println("撤销数据库备份...");// 撤销逻辑}@Overridepublic String getDescription() {return "数据库备份";}
}// 命令调度器
@Component
public class TaskScheduler {private final Map<String, TaskCommand> commands = new HashMap<>();@Autowiredpublic TaskScheduler(List<TaskCommand> commandList) {for (TaskCommand command : commandList) {commands.put(command.getDescription(), command);}}public void executeCommand(String commandName) {TaskCommand command = commands.get(commandName);if (command != null) {command.execute();} else {System.out.println("命令不存在: " + commandName);}}public void listCommands() {System.out.println("可用命令:");commands.keySet().forEach(System.out::println);}
}

Spring MVC中的命令模式

// 命令对象
public class UserRegistrationCommand {private String username;private String email;private String password;// getter和setter方法public void validate() {if (username == null || username.trim().isEmpty()) {throw new IllegalArgumentException("用户名不能为空");}if (email == null || !email.contains("@")) {throw new IllegalArgumentException("邮箱格式不正确");}}
}// 命令处理器
@Service
public class UserRegistrationHandler {@Autowiredprivate UserService userService;@Autowiredprivate EmailService emailService;public void handle(UserRegistrationCommand command) {// 验证命令command.validate();// 执行注册User user = userService.register(command.getUsername(), command.getEmail(), command.getPassword());// 发送确认邮件emailService.sendConfirmationEmail(user.getEmail());}
}// 控制器
@RestController
@RequestMapping("/api/users")
public class UserController {@Autowiredprivate UserRegistrationHandler registrationHandler;@PostMapping("/register")public ResponseEntity<String> register(@RequestBody UserRegistrationCommand command) {try {registrationHandler.handle(command);return ResponseEntity.ok("注册成功");} catch (Exception e) {return ResponseEntity.badRequest().body(e.getMessage());}}
}

具体使用场景

1. 智能家居控制系统

// 设备接口
public interface Device {void on();void off();boolean isOn();
}// 具体设备
public class Light implements Device {private boolean isOn = false;@Overridepublic void on() {isOn = true;System.out.println("灯已打开");}@Overridepublic void off() {isOn = false;System.out.println("灯已关闭");}@Overridepublic boolean isOn() {return isOn;}
}// 命令接口
public interface Command {void execute();void undo();
}// 具体命令
public class DeviceOnCommand implements Command {private Device device;public DeviceOnCommand(Device device) {this.device = device;}@Overridepublic void execute() {device.on();}@Overridepublic void undo() {device.off();}
}// 智能遥控器
public class SmartRemote {private Map<String, Command> commands = new HashMap<>();private Stack<Command> history = new Stack<>();public void setCommand(String button, Command command) {commands.put(button, command);}public void pressButton(String button) {Command command = commands.get(button);if (command != null) {command.execute();history.push(command);}}public void undo() {if (!history.isEmpty()) {Command command = history.pop();command.undo();}}
}

2. 文本编辑器

// 文档类
public class Document {private StringBuilder content = new StringBuilder();public void insert(int position, String text) {content.insert(position, text);}public void delete(int start, int end) {content.delete(start, end);}public String getContent() {return content.toString();}
}// 命令接口
public interface TextCommand {void execute();void undo();
}// 插入命令
public class InsertCommand implements TextCommand {private Document document;private int position;private String text;public InsertCommand(Document document, int position, String text) {this.document = document;this.position = position;this.text = text;}@Overridepublic void execute() {document.insert(position, text);}@Overridepublic void undo() {document.delete(position, position + text.length());}
}// 删除命令
public class DeleteCommand implements TextCommand {private Document document;private int start;private int end;private String deletedText;public DeleteCommand(Document document, int start, int end) {this.document = document;this.start = start;this.end = end;this.deletedText = document.getContent().substring(start, end);}@Overridepublic void execute() {document.delete(start, end);}@Overridepublic void undo() {document.insert(start, deletedText);}
}// 编辑器
public class TextEditor {private Document document = new Document();private Stack<TextCommand> history = new Stack<>();private Stack<TextCommand> redoHistory = new Stack<>();public void insert(int position, String text) {TextCommand command = new InsertCommand(document, position, text);command.execute();history.push(command);redoHistory.clear();}public void delete(int start, int end) {TextCommand command = new DeleteCommand(document, start, end);command.execute();history.push(command);redoHistory.clear();}public void undo() {if (!history.isEmpty()) {TextCommand command = history.pop();command.undo();redoHistory.push(command);}}public void redo() {if (!redoHistory.isEmpty()) {TextCommand command = redoHistory.pop();command.execute();history.push(command);}}public String getContent() {return document.getContent();}
}

3. 任务调度系统

// 任务命令接口
public interface TaskCommand {void execute();void cancel();String getTaskId();TaskStatus getStatus();
}// 任务状态
public enum TaskStatus {PENDING, RUNNING, COMPLETED, FAILED, CANCELLED
}// 具体任务命令
public class DataProcessingTask implements TaskCommand {private String taskId;private TaskStatus status = TaskStatus.PENDING;private String dataSource;private String outputPath;public DataProcessingTask(String taskId, String dataSource, String outputPath) {this.taskId = taskId;this.dataSource = dataSource;this.outputPath = outputPath;}@Overridepublic void execute() {status = TaskStatus.RUNNING;try {System.out.println("开始处理数据: " + dataSource);// 模拟数据处理Thread.sleep(5000);System.out.println("数据处理完成,输出到: " + outputPath);status = TaskStatus.COMPLETED;} catch (InterruptedException e) {status = TaskStatus.CANCELLED;Thread.currentThread().interrupt();} catch (Exception e) {status = TaskStatus.FAILED;System.err.println("任务执行失败: " + e.getMessage());}}@Overridepublic void cancel() {status = TaskStatus.CANCELLED;System.out.println("任务已取消: " + taskId);}@Overridepublic String getTaskId() {return taskId;}@Overridepublic TaskStatus getStatus() {return status;}
}// 任务调度器
public class TaskScheduler {private Map<String, TaskCommand> tasks = new HashMap<>();private ExecutorService executor = Executors.newFixedThreadPool(10);public void submitTask(TaskCommand task) {tasks.put(task.getTaskId(), task);executor.submit(() -> task.execute());}public void cancelTask(String taskId) {TaskCommand task = tasks.get(taskId);if (task != null) {task.cancel();}}public TaskStatus getTaskStatus(String taskId) {TaskCommand task = tasks.get(taskId);return task != null ? task.getStatus() : null;}public void shutdown() {executor.shutdown();}
}

4. 数据库事务管理

// 数据库操作命令
public interface DatabaseCommand {void execute() throws SQLException;void rollback() throws SQLException;String getDescription();
}// 插入命令
public class InsertCommand implements DatabaseCommand {private Connection connection;private String sql;private Object[] parameters;public InsertCommand(Connection connection, String sql, Object... parameters) {this.connection = connection;this.sql = sql;this.parameters = parameters;}@Overridepublic void execute() throws SQLException {try (PreparedStatement stmt = connection.prepareStatement(sql)) {for (int i = 0; i < parameters.length; i++) {stmt.setObject(i + 1, parameters[i]);}stmt.executeUpdate();}}@Overridepublic void rollback() throws SQLException {// 插入操作的回滚需要删除记录// 这里简化处理System.out.println("回滚插入操作");}@Overridepublic String getDescription() {return "INSERT: " + sql;}
}// 更新命令
public class UpdateCommand implements DatabaseCommand {private Connection connection;private String sql;private Object[] parameters;private Object[] originalValues;public UpdateCommand(Connection connection, String sql, Object[] parameters, Object[] originalValues) {this.connection = connection;this.sql = sql;this.parameters = parameters;this.originalValues = originalValues;}@Overridepublic void execute() throws SQLException {try (PreparedStatement stmt = connection.prepareStatement(sql)) {for (int i = 0; i < parameters.length; i++) {stmt.setObject(i + 1, parameters[i]);}stmt.executeUpdate();}}@Overridepublic void rollback() throws SQLException {// 更新操作的回滚需要恢复原值String rollbackSql = sql.replace("SET", "SET").replace("WHERE", "WHERE");try (PreparedStatement stmt = connection.prepareStatement(rollbackSql)) {for (int i = 0; i < originalValues.length; i++) {stmt.setObject(i + 1, originalValues[i]);}stmt.executeUpdate();}}@Overridepublic String getDescription() {return "UPDATE: " + sql;}
}// 事务管理器
public class TransactionManager {private List<DatabaseCommand> commands = new ArrayList<>();private Connection connection;public TransactionManager(Connection connection) {this.connection = connection;}public void addCommand(DatabaseCommand command) {commands.add(command);}public void execute() throws SQLException {try {connection.setAutoCommit(false);for (DatabaseCommand command : commands) {command.execute();}connection.commit();System.out.println("事务提交成功");} catch (SQLException e) {connection.rollback();System.out.println("事务回滚");throw e;} finally {connection.setAutoCommit(true);}}public void rollback() throws SQLException {try {connection.setAutoCommit(false);// 逆序回滚for (int i = commands.size() - 1; i >= 0; i--) {commands.get(i).rollback();}connection.commit();System.out.println("事务回滚完成");} catch (SQLException e) {System.err.println("回滚失败: " + e.getMessage());throw e;} finally {connection.setAutoCommit(true);}}
}

面试高频点

面试知识点思维导图

命令模式面试点
基本概念
实现方式
重难点
Spring应用
设计原则
实际应用
封装请求
解耦调用者
支持撤销
支持宏命令
Command接口
ConcreteCommand
Invoker调用者
Receiver接收者
撤销重做
宏命令
命令队列
持久化
CommandLineRunner
ApplicationRunner
MVC命令对象
任务调度
开闭原则
单一职责
依赖倒置
智能家居
文本编辑器
任务调度
事务管理

1. 命令模式的基本概念

问题:什么是命令模式?

答案要点:

  • 将请求封装成对象,使请求参数化
  • 解耦调用者和接收者
  • 支持撤销、重做、宏命令等功能
  • 属于行为型设计模式
问题:命令模式有哪些角色?

答案要点:

  • Command(命令接口):声明执行操作的接口
  • ConcreteCommand(具体命令):实现命令接口,绑定接收者
  • Invoker(调用者):调用命令对象执行请求
  • Receiver(接收者):知道如何执行与请求相关的操作
  • Client(客户端):创建具体命令对象并设置接收者

2. 实现方式相关

问题:如何实现命令模式?

答案要点:

// 1. 定义命令接口
public interface Command {void execute();void undo();
}// 2. 定义接收者
public class Light {public void turnOn() { System.out.println("灯已打开"); }public void turnOff() { System.out.println("灯已关闭"); }
}// 3. 实现具体命令
public class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOn();}@Overridepublic void undo() {light.turnOff();}
}// 4. 定义调用者
public class RemoteControl {private Command command;public void setCommand(Command command) {this.command = command;}public void pressButton() {command.execute();}
}

3. 重难点问题

问题:如何实现命令的撤销和重做?

答案要点:

// 1. 保存命令历史
public class CommandHistory {private Stack<Command> history = new Stack<>();private Stack<Command> redoHistory = new Stack<>();public void executeCommand(Command command) {command.execute();history.push(command);redoHistory.clear();}public void undo() {if (!history.isEmpty()) {Command command = history.pop();command.undo();redoHistory.push(command);}}public void redo() {if (!redoHistory.isEmpty()) {Command command = redoHistory.pop();command.execute();history.push(command);}}
}// 2. 保存状态信息
public class LightOnCommand implements Command {private Light light;private boolean previousState;@Overridepublic void execute() {previousState = light.isOn();light.turnOn();}@Overridepublic void undo() {if (previousState) {light.turnOn();} else {light.turnOff();}}
}
问题:如何实现宏命令?

答案要点:

public class MacroCommand implements Command {private List<Command> commands;public MacroCommand(List<Command> commands) {this.commands = commands;}@Overridepublic void execute() {for (Command command : commands) {command.execute();}}@Overridepublic void undo() {// 逆序执行撤销for (int i = commands.size() - 1; i >= 0; i--) {commands.get(i).undo();}}
}

4. Spring中的应用

问题:Spring中如何使用命令模式?

答案要点:

// 1. CommandLineRunner接口
@Component
public class DatabaseInitializer implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {System.out.println("初始化数据库...");}
}// 2. ApplicationRunner接口
@Component
public class ConfigLoader implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {System.out.println("加载配置...");}
}// 3. MVC中的命令对象
@RestController
public class UserController {@PostMapping("/users")public ResponseEntity<String> createUser(@RequestBody UserCreateCommand command) {// 处理命令return ResponseEntity.ok("用户创建成功");}
}

5. 设计原则相关

问题:命令模式体现了哪些设计原则?

答案要点:

  • 开闭原则:可以添加新命令而不修改现有代码
  • 单一职责:每个命令只负责一个操作
  • 依赖倒置:依赖抽象而不是具体实现
  • 里氏替换:具体命令可以替换命令接口

6. 实际应用场景

问题:命令模式适用于哪些场景?

答案要点:

  • 智能家居:遥控器控制各种设备
  • 文本编辑器:撤销、重做功能
  • 任务调度:异步任务执行
  • 数据库事务:事务的提交和回滚
  • GUI操作:菜单、按钮操作
  • 日志记录:操作日志和审计

7. 与其他模式的对比

问题:命令模式与策略模式的区别?

答案要点:

  • 目的:命令模式封装请求,策略模式封装算法
  • 调用时机:命令模式可以延迟调用,策略模式立即调用
  • 撤销支持:命令模式支持撤销,策略模式不支持
  • 复杂度:命令模式更复杂,策略模式更简单
问题:命令模式与模板方法模式的区别?

答案要点:

  • 结构:命令模式是对象行为,模板方法是类行为
  • 继承:命令模式使用组合,模板方法使用继承
  • 灵活性:命令模式更灵活,模板方法相对固定
  • 使用场景:命令模式用于请求封装,模板方法用于算法框架

总结

命令模式是一种强大的行为型设计模式,它通过将请求封装成对象,实现了调用者和接收者的解耦,并提供了撤销、重做、宏命令等强大功能。

核心优势

  1. 解耦:调用者和接收者松耦合
  2. 灵活性:支持撤销、重做、宏命令
  3. 扩展性:易于添加新命令
  4. 可维护性:命令可以独立测试和维护

注意事项

  1. 复杂度:增加了系统的复杂度
  2. 内存消耗:需要保存命令历史
  3. 性能考虑:大量命令时需要考虑性能
  4. 状态管理:撤销功能需要合理管理状态

在实际开发中,命令模式特别适用于需要支持撤销操作、宏命令、任务调度等场景。通过合理使用命令模式,可以大大提高系统的灵活性和可维护性。

http://www.dtcms.com/a/391506.html

相关文章:

  • 谈一谈Java成员变量,局部变量和静态变量的创建和回收时机
  • OSCP - Proving Grounds - Leyla
  • 9 月 19 日 IT 界热点大赏:科技浪潮下的创新与变革
  • 自动化脚本的零失误之路
  • Redis(三)Redis集群的三种模式
  • 网络环路:成因、影响与防环机制深度解析
  • 力扣刷题笔记(1)--面试150数组部分
  • 分割模型Maskformer
  • C# TCP的方式 实现上传文件
  • 高压消解罐:难溶物质消解的首选工具
  • JavaScript 字符串截取最后一位的几种方法
  • MobileNetV3训练自定义数据集并通过C++进行推理模型部署
  • nvshmem源码学习(一)ibgda视角的整体流程
  • Redis群集的三种模式
  • 鸿蒙(南向/北向)
  • Spring IoCDI 快速入门
  • MySQL的C语言驱动核心——`mysql_real_connect()` 函数
  • C++线程池学习 Day06
  • React 样式CSS的定义 多种定义方式 前端基础
  • react+anddesign组件Tabs实现后台管理系统自定义页签头
  • Midscene 低代码实现Android自动化
  • ADB使用指南
  • FunCaptcha如何查找sitekey参数
  • 大模型如何让机器人实现“从冰箱里拿一瓶可乐”?
  • Python实现液体蒸发优化算法 (Evaporation Rate Water Cycle Algorithm, ER-WCA)(附完整代码)
  • MySQL 数据库的「超级钥匙」—`mysql_real_connect`
  • LeetCode 每日一题 3484. 设计电子表格
  • RAGAS深度解析:引领RAG评估新时代的开源技术革命
  • aave v3.4 利率计算详解
  • rook-ceph CRD资源配置时效问题