GwWuYou 5aa11ddc41 feat(architecture): 添加架构核心组件与命令模式实现
- 新增 Architecture 基类与 IArchitecture 接口,实现单例模式与组件注册管理
- 集成 IOC 容器支持系统、模型、工具的依赖注入与生命周期管理
- 实现命令模式基础类 AbstractCommand 与接口 ICommand,支持带返回值命令
- 提供事件系统集成,支持事件的发布与订阅机制
- 添加控制器接口 IController,整合命令发送、事件注册与模型获取能力
- 创建详细的 README 文档说明各组件使用方式与设计模式应用
- 支持命令、查询、事件的统一调度与解耦通信机制
2025-12-09 15:32:17 +08:00

293 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Command 包使用说明
## 概述
Command 包实现了命令模式Command Pattern用于封装用户操作和业务逻辑。通过命令模式可以将请求封装为对象实现操作的参数化、队列化、日志记录、撤销等功能。
## 核心接口
### 1. [`ICommand`](ICommand.cs)
无返回值命令接口,定义了命令的基本契约。
**继承的能力接口:**
- [`ICanSetArchitecture`](../rule/ICanSetArchitecture.cs) - 可设置架构
- [`ICanGetSystem`](../system/ICanGetSystem.cs) - 可获取系统
- [`ICanGetModel`](../model/ICanGetModel.cs) - 可获取模型
- [`ICanGetUtility`](../utility/ICanGetUtility.cs) - 可获取工具
- [`ICanSendEvent`](../events/ICanSendEvent.cs) - 可发送事件
- [`ICanSendCommand`](ICanSendCommand.cs) - 可发送命令
- [`ICanSendQuery`](../query/ICanSendQuery.cs) - 可发送查询
**核心方法:**
```csharp
void Execute(); // 执行命令
```
### 2. [`ICommand<TResult>`](ICommand.cs)
带返回值的命令接口,用于需要返回执行结果的命令。
**核心方法:**
```csharp
TResult Execute(); // 执行命令并返回结果
```
### 3. [`ICanSendCommand`](ICanSendCommand.cs)
标记接口,表示实现者可以发送命令。继承自 [`IBelongToArchitecture`](../rule/IBelongToArchitecture.cs)。
## 核心类
### 1. [`AbstractCommand`](AbstractCommand.cs)
无返回值命令的抽象基类,提供了命令的基础实现。
**使用示例:**
```csharp
// 定义一个开始游戏的命令
public class StartGameCommand : AbstractCommand
{
protected override void OnExecute()
{
// 获取需要的模型
var playerModel = this.GetModel<PlayerModel>();
var gameModel = this.GetModel<GameModel>();
// 执行业务逻辑
playerModel.Health.Value = 100;
gameModel.GameState.Value = GameState.Playing;
// 发送事件通知其他模块
this.SendEvent(new GameStartedEvent());
}
}
// 使用命令
public class GameController : IController
{
public IArchitecture GetArchitecture() => GameArchitecture.Interface;
public void OnStartButtonClicked()
{
// 方式1发送命令实例
this.SendCommand(new StartGameCommand());
// 方式2通过泛型发送需要无参构造函数
this.SendCommand<StartGameCommand>();
}
}
```
### 2. [`AbstractCommand<TResult>`](AbstractCommand.cs)
带返回值命令的抽象基类。
**使用示例:**
```csharp
// 定义一个计算伤害的命令
public class CalculateDamageCommand : AbstractCommand<int>
{
private readonly int _attackPower;
private readonly int _defense;
public CalculateDamageCommand(int attackPower, int defense)
{
_attackPower = attackPower;
_defense = defense;
}
protected override int OnExecute()
{
// 获取游戏配置
var config = this.GetModel<GameConfigModel>();
// 计算最终伤害
var baseDamage = _attackPower - _defense;
var finalDamage = Math.Max(1, baseDamage * config.DamageMultiplier);
return (int)finalDamage;
}
}
// 使用带返回值的命令
public class CombatSystem : AbstractSystem
{
protected override void OnInit() { }
public void Attack(Character attacker, Character defender)
{
// 发送命令并获取返回值
var damage = this.SendCommand(
new CalculateDamageCommand(attacker.AttackPower, defender.Defense)
);
// 应用伤害
defender.Health -= damage;
// 发送伤害事件
this.SendEvent(new DamageDealtEvent(attacker, defender, damage));
}
}
```
## 命令的生命周期
1. **创建命令**:实例化命令对象,传入必要的参数
2. **设置架构**:框架自动调用 `SetArchitecture()` 设置架构引用
3. **执行命令**:调用 `Execute()` 方法,内部委托给 `OnExecute()`
4. **返回结果**:对于带返回值的命令,返回执行结果
5. **命令销毁**:命令执行完毕后可以被垃圾回收
## 使用场景
### 1. 用户交互操作
```csharp
// UI 按钮点击
public class SaveGameCommand : AbstractCommand
{
protected override void OnExecute()
{
var saveSystem = this.GetSystem<SaveSystem>();
var playerModel = this.GetModel<PlayerModel>();
saveSystem.SavePlayerData(playerModel);
this.SendEvent(new GameSavedEvent());
}
}
```
### 2. 业务流程控制
```csharp
// 关卡切换
public class LoadLevelCommand : AbstractCommand
{
private readonly int _levelId;
public LoadLevelCommand(int levelId)
{
_levelId = levelId;
}
protected override void OnExecute()
{
var levelSystem = this.GetSystem<LevelSystem>();
var uiSystem = this.GetSystem<UISystem>();
// 显示加载界面
uiSystem.ShowLoadingScreen();
// 加载关卡
levelSystem.LoadLevel(_levelId);
// 发送事件
this.SendEvent(new LevelLoadedEvent(_levelId));
}
}
```
### 3. 网络请求封装
```csharp
// 登录命令
public class LoginCommand : AbstractCommand<bool>
{
private readonly string _username;
private readonly string _password;
public LoginCommand(string username, string password)
{
_username = username;
_password = password;
}
protected override bool OnExecute()
{
var networkSystem = this.GetSystem<NetworkSystem>();
var playerModel = this.GetModel<PlayerModel>();
// 发送登录请求
var result = networkSystem.Login(_username, _password);
if (result.Success)
{
playerModel.UserId = result.UserId;
playerModel.Username = _username;
this.SendEvent(new LoginSuccessEvent());
return true;
}
else
{
this.SendEvent(new LoginFailedEvent(result.ErrorMessage));
return false;
}
}
}
```
## 命令 vs 系统方法
**何时使用命令:**
- 需要参数化操作
- 需要记录操作历史(用于撤销/重做)
- 操作需要跨多个系统协调
- 用户触发的离散操作
**何时使用系统方法:**
- 持续运行的逻辑(如每帧更新)
- 系统内部的私有逻辑
- 不需要外部调用的功能
## 最佳实践
1. **保持命令原子性**:一个命令应该完成一个完整的业务操作
2. **命令无状态**:命令不应该保存长期状态,执行完即可丢弃
3. **参数通过构造函数传递**:命令需要的参数应在创建时传入
4. **避免命令嵌套**:命令内部尽量不要发送其他命令,使用事件通信
5. **合理使用返回值**:只在确实需要返回结果时使用 `ICommand<TResult>`
6. **命令命名规范**:使用动词+名词形式,如 `StartGameCommand``SavePlayerCommand`
## 扩展功能
### 命令撤销/重做(可扩展)
```csharp
// 可撤销命令接口
public interface IUndoableCommand : ICommand
{
void Undo();
}
// 实现可撤销命令
public class MoveCommand : AbstractCommand, IUndoableCommand
{
private Vector3 _oldPosition;
private Vector3 _newPosition;
protected override void OnExecute()
{
var player = this.GetModel<PlayerModel>();
_oldPosition = player.Position;
player.Position = _newPosition;
}
public void Undo()
{
var player = this.GetModel<PlayerModel>();
player.Position = _oldPosition;
}
}
```
## 相关包
- [`architecture`](../architecture/README.md) - 架构核心,负责命令的分发和执行
- [`extensions`](../extensions/README.md) - 提供 `SendCommand()` 扩展方法
- [`query`](../query/README.md) - 查询模式,用于数据查询
- [`events`](../events/README.md) - 事件系统,命令执行后的通知机制
- [`system`](../system/README.md) - 业务系统,命令的主要执行者
- [`model`](../model/README.md) - 数据模型,命令操作的数据