Unity项目中Command模式应用是否正确?无Invoker实现疑问
你的实现是否符合Command模式规范?
你的实现已经符合Command模式的核心规范,但没有引入Invoker(调用者)确实会丢失这个模式的部分扩展能力,下面具体拆解:
符合规范的核心点
- 你定义了抽象的
iCommand接口,约定了Execute()方法,这是Command模式的核心契约,保证所有命令都遵循统一的执行标准。 GenerateCommand作为具体命令类,完整封装了生成操作的逻辑(销毁旧地图、设置尺寸、生成、构建),同时持有执行所需的接收者(Generator)和依赖控件(Slider),完全符合“将请求封装为对象”的模式核心思想。- 调用端(
AppController的Generate()方法)通过命令对象间接执行操作,实现了调用者(按钮触发逻辑)和接收者(Generator)的解耦——按钮不需要知道Generator的具体方法,只需要调用命令的Execute()。
缺少Invoker的影响
目前你的AppController实际上承担了部分Invoker的职责,但没有将命令管理的逻辑抽离出来:
- 无法方便地扩展命令的撤销/重做功能:如果后续需要支持撤销生成操作,你得在
AppController里维护命令历史,会让控制器逻辑变得臃肿。 - 难以实现批量命令执行、命令队列等功能:比如要同时执行多个命令(生成+初始化玩家位置),直接在控制器里写会破坏单一职责。
- 命令的执行逻辑和控制器耦合:每次修改命令执行的规则(比如加日志、加延迟),都要改动
AppController。
优化建议:添加Invoker
可以创建一个简单的CommandInvoker类来专门管理命令的执行和历史:
public class CommandInvoker { private Stack<iCommand> _commandHistory = new Stack<iCommand>(); public void ExecuteCommand(iCommand command) { command.Execute(); _commandHistory.Push(command); } // 扩展撤销功能 public void UndoLastCommand() { if (_commandHistory.Count > 0) { // 这里需要你的Command接口添加Undo方法 var lastCommand = _commandHistory.Pop(); if (lastCommand is IUndoableCommand undoable) { undoable.Undo(); } } } } // 扩展支持撤销的命令接口 public interface IUndoableCommand : iCommand { void Undo(); } // 修改GenerateCommand实现Undo public class GenerateCommand : IUndoableCommand { private Generator _generator; private Slider _sliderWidth, _sliderHeight; // 记录撤销所需的旧状态 private int _oldWidth; private int _oldHeight; public GenerateCommand(Generator generator, Slider sliderWidth, Slider sliderHeight) { _generator = generator; _sliderWidth = sliderWidth; _sliderHeight = sliderHeight; // 保存旧状态用于撤销 _oldWidth = generator.GetWidth(); _oldHeight = generator.GetHeight(); } public void Execute() { _generator.Destroy(); _generator.SetWidth((int)_sliderWidth.value); _generator.SetHeight((int)_sliderHeight.value); _generator.Generate(); _generator.Build(); } public void Undo() { _generator.Destroy(); _generator.SetWidth(_oldWidth); _generator.SetHeight(_oldHeight); _generator.Generate(); _generator.Build(); } }
然后修改AppController,依赖CommandInvoker:
public class AppController : MonoBehaviour { public Generator generator; public Slider sliderWidth, sliderHeight; public GameObject generatorController, playerController, UI, app, room, spawnLocation; private CommandInvoker _invoker; void Start() { _invoker = new CommandInvoker(); generator = new DepthFirstSearchGenerator(room: room, spawnLocation: spawnLocation); Generate(); } public void Generate() { var command = new GenerateCommand(generator, sliderWidth, sliderHeight); _invoker.ExecuteCommand(command); } // 可以添加按钮调用撤销方法 public void UndoGenerate() { _invoker.UndoLastCommand(); } }
这样既保留了Command模式的解耦优势,又通过Invoker获得了扩展命令管理能力的空间。
内容的提问来源于stack exchange,提问作者Lucas Luque
相关产品推荐
相关产品推荐

