文章目录
- ⌨️ 命令模式(Command Pattern)深度解析
- 一、模式本质与核心价值
- 二、经典UML结构
- 三、Unity实战代码(可撤销的建造系统)
- 1. 定义命令接口与接收者
- 2. 实现具体命令
- 3. 命令管理器(Invoker)
- 4. 客户端使用
- 四、模式进阶技巧
- 1. 宏命令(组合命令)
- 2. 异步命令执行
- 3. 命令序列化
- 五、游戏开发典型应用场景
- 六、性能优化策略
- 七、模式对比与选择
- 八、最佳实践原则
- 九、常见问题解决方案
⌨️ 命令模式(Command Pattern)深度解析
——以Unity实现可撤销操作与智能输入系统为核心案例
一、模式本质与核心价值
核心目标:
✅ 封装操作为对象,支持撤销/重做功能
✅ 解耦请求发送者与执行者,提升系统扩展性
✅ 支持请求队列与日志记录,实现复杂操作管理
关键术语:
- Command(命令接口):定义执行操作的统一接口
- ConcreteCommand(具体命令):实现具体业务逻辑
- Invoker(调用者):触发命令执行(如输入处理器)
- Receiver(接收者):实际执行操作的对象
数学表达:
操作历史H可表示为命令序列:
H = [C₁, C₂, …, Cₙ]
撤销操作为:H.pop() → ExecuteInverse(Cₙ)
二、经典UML结构
三、Unity实战代码(可撤销的建造系统)
1. 定义命令接口与接收者
public interface ICommand {void Execute();void Undo();
}public class Builder : MonoBehaviour {public void BuildWall(Vector3 position) {Instantiate(wallPrefab, position, Quaternion.identity);}public void DestroyWall(Vector3 position) {var wall = Physics.OverlapSphere(position, 0.5f).FirstOrDefault(c => c.CompareTag("Wall"));if(wall != null) Destroy(wall.gameObject);}
}
2. 实现具体命令
public class BuildCommand : ICommand {private Builder _builder;private Vector3 _position;private GameObject _builtWall;public BuildCommand(Builder builder, Vector3 pos) {_builder = builder;_position = pos;}public void Execute() {_builder.BuildWall(_position);_builtWall = GameObject.FindWithTag("Wall");}public void Undo() {if(_builtWall != null) {_builder.DestroyWall(_builtWall.transform.position);}}
}
3. 命令管理器(Invoker)
public class CommandManager : MonoBehaviour {private Stack<ICommand> _commandHistory = new();private Stack<ICommand> _redoStack = new();public void ExecuteCommand(ICommand command) {command.Execute();_commandHistory.Push(command);_redoStack.Clear();}public void Undo() {if(_commandHistory.Count == 0) return;var cmd = _commandHistory.Pop();cmd.Undo();_redoStack.Push(cmd);}public void Redo() {if(_redoStack.Count == 0) return;var cmd = _redoStack.Pop();cmd.Execute();_commandHistory.Push(cmd);}
}
4. 客户端使用
public class BuildController : MonoBehaviour {[SerializeField] private Builder builder;[SerializeField] private CommandManager cmdManager;void Update() {if(Input.GetMouseButtonDown(0)) {var ray = Camera.main.ScreenPointToRay(Input.mousePosition);if(Physics.Raycast(ray, out var hit)) {var cmd = new BuildCommand(builder, hit.point);cmdManager.ExecuteCommand(cmd);}}if(Input.GetKeyDown(KeyCode.Z)) cmdManager.Undo();if(Input.GetKeyDown(KeyCode.Y)) cmdManager.Redo();}
}
四、模式进阶技巧
1. 宏命令(组合命令)
public class MacroCommand : ICommand {private List<ICommand> _commands = new();public void Add(ICommand cmd) => _commands.Add(cmd);public void Execute() {foreach(var cmd in _commands) cmd.Execute();}public void Undo() {foreach(var cmd in _commands.AsEnumerable().Reverse()) {cmd.Undo();}}
}
2. 异步命令执行
public class AsyncMoveCommand : ICommand {public async Task ExecuteAsync() {await MoveCoroutine();}private IEnumerator MoveCoroutine() {// 移动动画协程}
}
3. 命令序列化
[System.Serializable]
public class SaveCommand : ICommand {public string SaveData;public void Execute() {PlayerPrefs.SetString("Save", SaveData);}public void Undo() {PlayerPrefs.DeleteKey("Save");}
}
五、游戏开发典型应用场景
-
输入映射系统
public class InputSystem {private Dictionary<KeyCode, ICommand> _keyBindings = new();public void Update() {foreach(var binding in _keyBindings) {if(Input.GetKeyDown(binding.Key)) {binding.Value.Execute();}}} }
-
AI行为队列
public class AICommander {private Queue<ICommand> _actionQueue = new();public void ScheduleAction(ICommand cmd) {_actionQueue.Enqueue(cmd);}void Update() {if(_actionQueue.Count > 0) {_actionQueue.Dequeue().Execute();}} }
-
网络命令同步
public class NetworkCommand : ICommand {public void Execute() {if(PhotonNetwork.IsMasterClient) {photonView.RPC("RpcExecute", RpcTarget.All);}}[PunRPC]private void RpcExecute() {// 实际执行逻辑} }
-
回放系统
public class ReplaySystem {private List<TimestampedCommand> _commandLog = new();public void Record(ICommand cmd) {_commandLog.Add(new TimestampedCommand(Time.time, cmd));}public void PlayReplay() {StartCoroutine(ReplayCommands());} }
六、性能优化策略
策略 | 实现方式 | 适用场景 |
---|---|---|
命令池 | 重用命令对象 | 高频命令创建 |
批量处理 | 合并相似命令 | 大量小操作 |
延迟执行 | 分帧处理命令队列 | 性能敏感场景 |
二进制序列化 | 优化存储空间 | 回放/存档系统 |
七、模式对比与选择
维度 | 命令模式 | 策略模式 |
---|---|---|
目的 | 封装操作 | 替换算法 |
状态管理 | 支持撤销 | 无状态 |
执行时机 | 可延迟执行 | 立即执行 |
典型应用 | 输入处理 | AI决策 |
八、最佳实践原则
- 接口最小化:保持命令接口简洁
- 不可变状态:命令参数应在构造时确定
- 原子操作:每个命令代表一个完整操作
- 安全撤销:确保Undo操作的幂等性
public void Undo() {if(_isUndone) return;// 撤销逻辑_isUndone = true; }
九、常见问题解决方案
Q1:如何处理命令依赖?
→ 实现命令版本控制
public class VersionedCommand : ICommand {public int Version;public bool IsCompatibleWith(int currentVersion) {return Version <= currentVersion;}
}
Q2:如何优化大量命令存储?
→ 使用增量压缩
public class DeltaCommand : ICommand {private byte[] _deltaData;public void Compress(CommandState fullState) {// 计算差异并压缩}
}
Q3:如何处理网络延迟?
→ 实现预测回滚
public class PredictiveMoveCommand : ICommand {public void Execute() {_predictedPosition = CalculatePrediction();_serverPosition = NetworkSync();if(_predictedPosition != _serverPosition) {RollbackAndResync();}}
}
上一篇 【行为型之责任链模式】游戏开发实战——Unity灵活事件处理系统的架构核心
下一篇 【行为型之解释器模式】游戏开发实战——Unity动态公式解析与脚本系统的架构奥秘