GFramework/docs/zh-CN/core/command.md
GeWuYou b835d3af67 docs(site): 实现多语言支持并重构文档站点配置
- 添加简体中文本地化配置和导航链接
- 配置本地搜索功能并设置中文翻译
- 添加 Catch-all 404 重定向中间件
- 重构侧边栏和导航结构以支持国际化
- 移除旧的英文文档内容并更新配置
- 添加页脚导航和面包屑文字本地化
2026-02-11 12:52:14 +08:00

8.6 KiB
Raw Blame History

Command 包使用说明

概述

Command 包实现了命令模式Command Pattern用于封装用户操作和业务逻辑。通过命令模式可以将请求封装为对象实现操作的参数化、队列化、日志记录、撤销等功能。

核心接口

1. ICommand

无返回值命令接口,定义了命令的基本契约。

核心方法:

void Execute();  // 执行命令

2. ICommand<TResult>

带返回值的命令接口,用于需要返回执行结果的命令。

核心方法:

TResult Execute();  // 执行命令并返回结果

核心类

1. AbstractCommand<TInput>

无返回值命令的抽象基类,提供了命令的基础实现。它继承自 ContextAwareBase ,具有上下文感知能力。

使用示例:

// 定义一个命令输入参数
public struct StartGameCommandInput : ICommandInput
{
    public int LevelId { get; set; }
    public string PlayerName { get; set; }
}

// 定义一个开始游戏的命令
public class StartGameCommand : AbstractCommand<StartGameCommandInput>
{
    public StartGameCommand(StartGameCommandInput input) : base(input)
    {
    }

    protected override void OnExecute(StartGameCommandInput input)
    {
        // 获取需要的模型
        var playerModel = this.GetModel<PlayerModel>();
        var gameModel = this.GetModel<GameModel>();
        
        // 执行业务逻辑
        playerModel.PlayerName.Value = input.PlayerName;
        gameModel.CurrentLevel.Value = input.LevelId;
        gameModel.GameState.Value = GameState.Playing;
        
        // 发送事件通知其他模块
        this.SendEvent(new GameStartedEvent());
    }
}

// 使用命令
public class GameController : IController
{
    public IArchitecture GetArchitecture() => GameArchitecture.Interface;
    
    public void OnStartButtonClicked()
    {
        // 发送命令实例
        this.SendCommand(new StartGameCommand(new StartGameCommandInput 
        { 
            LevelId = 1, 
            PlayerName = "Player1" 
        }));
    }
}

2. AbstractCommand<TInput, TResult>

带返回值命令的抽象基类,同样继承自 ContextAwareBase

使用示例:

// 定义一个计算伤害的命令输入
public struct CalculateDamageCommandInput : ICommandInput
{
    public int AttackerAttackPower { get; set; }
    public int DefenderDefense { get; set; }
}

// 定义一个计算伤害的命令
public class CalculateDamageCommand : AbstractCommand<CalculateDamageCommandInput, int>
{
    public CalculateDamageCommand(CalculateDamageCommandInput input) : base(input)
    {
    }

    protected override int OnExecute(CalculateDamageCommandInput input)
    {
        // 获取游戏配置
        var config = this.GetModel<GameConfigModel>();
        
        // 计算最终伤害
        var baseDamage = input.AttackerAttackPower - input.DefenderDefense;
        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(new CalculateDamageCommandInput
        {
            AttackerAttackPower = attacker.AttackPower,
            DefenderDefense = defender.Defense
        }));
        
        // 应用伤害
        defender.Health -= damage;
        
        // 发送伤害事件
        this.SendEvent(new DamageDealtEvent(attacker, defender, damage));
    }
}

命令的生命周期

  1. 创建命令:实例化命令对象,传入必要的参数
  2. 执行命令:调用 Execute() 方法,内部委托给 OnExecute()
  3. 返回结果:对于带返回值的命令,返回执行结果
  4. 命令销毁:命令执行完毕后可以被垃圾回收

CommandBus - 命令总线

功能说明

CommandBus 是命令执行的核心组件,负责发送和执行命令。

主要方法:

void Send(ICommand command);              // 发送无返回值命令
TResult Send<TResult>(ICommand<TResult> command);  // 发送带返回值命令

使用示例

var commandBus = new CommandBus();

// 发送无返回值命令
commandBus.Send(new StartGameCommand(new StartGameCommandInput()));

// 发送带返回值命令
var result = commandBus.Send(new CalculateDamageCommand(new CalculateDamageCommandInput()));

EmptyCommandInput - 空命令输入

当命令不需要输入参数时,可以使用 EmptyCommandInput 类:

public class SimpleActionCommand : AbstractCommand<EmptyCommandInput>
{
    public SimpleActionCommand(EmptyCommandInput input) : base(input)
    {
    }

    protected override void OnExecute(EmptyCommandInput input)
    {
        // 执行简单操作,无需额外参数
        this.SendEvent(new SimpleActionEvent());
    }
}

使用场景

1. 用户交互操作

public struct SaveGameCommandInput : ICommandInput
{
    public string SaveSlot { get; set; }
}

public class SaveGameCommand : AbstractCommand<SaveGameCommandInput>
{
    public SaveGameCommand(SaveGameCommandInput input) : base(input)
    {
    }

    protected override void OnExecute(SaveGameCommandInput input)
    {
        var saveSystem = this.GetSystem<SaveSystem>();
        var playerModel = this.GetModel<PlayerModel>();
        
        saveSystem.SavePlayerData(playerModel, input.SaveSlot);
        this.SendEvent(new GameSavedEvent(input.SaveSlot));
    }
}

2. 业务流程控制

public struct LoadLevelCommandInput : ICommandInput
{
    public int LevelId { get; set; }
}

public class LoadLevelCommand : AbstractCommand<LoadLevelCommandInput>
{
    public LoadLevelCommand(LoadLevelCommandInput input) : base(input)
    {
    }

    protected override void OnExecute(LoadLevelCommandInput input)
    {
        var levelSystem = this.GetSystem<LevelSystem>();
        var uiSystem = this.GetSystem<UISystem>();
        
        // 显示加载界面
        uiSystem.ShowLoadingScreen();
        
        // 加载关卡
        levelSystem.LoadLevel(input.LevelId);
        
        // 发送事件
        this.SendEvent(new LevelLoadedEvent(input.LevelId));
    }
}

最佳实践

  1. 保持命令原子性:一个命令应该完成一个完整的业务操作
  2. 命令无状态:命令不应该保存长期状态,执行完即可丢弃
  3. 参数通过构造函数传递:命令需要的参数应在创建时传入
  4. 避免命令嵌套:命令内部尽量不要发送其他命令,使用事件通信
  5. 合理使用返回值:只在确实需要返回结果时使用 AbstractCommand<TInput, TResult>
  6. 命令命名规范:使用动词+名词形式,如 StartGameCommandSavePlayerCommand
  7. 输入参数结构化:使用 ICommandInput 接口的实现类来组织命令参数

扩展功能

命令撤销/重做(可扩展)

public struct MoveCommandInput : ICommandInput
{
    public Vector3 NewPosition { get; set; }
}

// 实现可撤销命令
public class MoveCommand : AbstractCommand<MoveCommandInput>, IUndoableCommand
{
    private Vector3 _oldPosition;
    private Vector3 _newPosition;
    
    public MoveCommand(MoveCommandInput input) : base(input)
    {
        _newPosition = input.NewPosition;
    }

    protected override void OnExecute(MoveCommandInput input)
    {
        var player = this.GetModel<PlayerModel>();
        _oldPosition = player.Position;
        player.Position = input.NewPosition;
    }
    
    public void Undo()
    {
        var player = this.GetModel<PlayerModel>();
        player.Position = _oldPosition;
    }
}

相关包

  • architecture - 架构核心,负责命令的分发和执行
  • extensions - 提供 SendCommand() 扩展方法
  • query - 查询模式,用于数据查询
  • events - 事件系统,命令执行后的通知机制
  • system - 业务系统,命令的主要执行者
  • model - 数据模型,命令操作的数据

许可证: Apache 2.0