--- prev: text: '引入 Model 重构' link: './04-model-refactor' next: text: 'Utility 与 System' link: './06-utility-system' --- # 第 5 章:命令系统优化 在上一章中,我们通过 Model 和事件系统实现了数据驱动的架构。但 Controller 仍然承担着交互逻辑,本章将引入 **Command(命令)模式 ** 进一步优化。 ## Controller 的职责问题 ### 当前代码 ```csharp public override void _Ready() { _counterModel = this.GetModel()!; AddButton.Pressed += () => { _counterModel.Increment(); // ← 交互逻辑 }; SubButton.Pressed += () => { _counterModel.Decrement(); // ← 交互逻辑 }; // ... } ``` 看起来很简洁,但这段代码同时承担着: - **表现逻辑**(View Binding):`AddButton.Pressed +=` - **交互逻辑**(Interaction Logic):`_counterModel.Increment()` ### 为什么这是问题? 现在只是简单的增减,但如果功能变复杂: ```csharp AddButton.Pressed += async () => { // 1. 验证状态 if (!CanIncrement()) return; // 2. 执行业务逻辑 await DoSomethingAsync(); _counterModel.Increment(); // 3. 保存数据 await SaveToFileAsync(); // 4. 播放音效 PlaySound("increment.wav"); // 5. 统计埋点 LogAnalytics("counter_incremented"); // 6. 更新成就 UpdateAchievement(); }; ``` **问题**: - Controller 迅速膨胀 - 逻辑难以复用(如果键盘快捷键也要增加计数?) - 难以测试(需要 mock 按钮) - 违反单一职责原则 ## 理解 Command 模式 ### Command 的作用 **Command(命令)** 是一种设计模式,它将"请求"封装成对象: ``` 用户操作 → Command → Model ``` 优势: - **解耦**:Controller 不关心如何增加计数,只负责"发送命令" - **复用**:同一个命令可以被多个地方调用 - **扩展**:新增逻辑只需修改命令,不影响 Controller - **可测试**:可以独立测试命令逻辑 ### 职责划分 | 层级 | 职责 | |----------------|------------| | **Controller** | 将用户操作转换为命令 | | **Command** | 封装具体的业务逻辑 | | **Model** | 存储状态,发送事件 | ## 创建 Command ### 1. 创建增加命令 在 `scripts/command/` 创建 `IncreaseCountCommand.cs`: ```csharp using GFramework.Core.Command; using GFramework.Core.Extensions; using MyGFrameworkGame.scripts.Model; namespace MyGFrameworkGame.scripts.Command; /// /// 增加计数器值的命令 /// public class IncreaseCountCommand : AbstractCommand { /// /// 执行命令的核心逻辑 /// protected override void OnExecute() { // 获取 Model 并调用方法 var model = this.GetModel()!; model.Increment(); } } ``` ::: tip AbstractCommand `AbstractCommand` 是 GFramework 提供的基类,它: - 自动注入 `Architecture` 上下文 - 提供 `GetModel`、`GetSystem`、`GetUtility` 等方法 - 管理命令的生命周期 ::: ### 2. 创建减少命令 在 `scripts/command/` 创建 `DecreaseCountCommand.cs`: ```csharp using GFramework.Core.Command; using GFramework.Core.Extensions; using MyGFrameworkGame.scripts.Model; namespace MyGFrameworkGame.scripts.Command; /// /// 减少计数器值的命令 /// public class DecreaseCountCommand : AbstractCommand { /// /// 执行命令的核心逻辑 /// protected override void OnExecute() { var model = this.GetModel()!; model.Decrement(); } } ``` ## 重构 Controller ### 使用命令替换直接调用 编辑 `App.cs`: ```csharp using GFramework.Core.Abstractions.Controller; using GFramework.Core.Extensions; using GFramework.SourceGenerators.Abstractions.Rule; using Godot; using MyGFrameworkGame.scripts.Command; using MyGFrameworkGame.scripts.Model; namespace MyGFrameworkGame.scripts.app; [ContextAware] public partial class App : Control, IController { private Button AddButton => GetNode