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

Rule 包使用说明

概述

Rule 包定义了框架的核心规则接口,这些接口规定了框架各个组件之间的关系和约束。所有框架组件都需要遵循这些规则接口。

核心接口

IBelongToArchitecture

标记接口,表示某个对象属于特定的架构体系。

接口定义:

public interface IBelongToArchitecture
{
    IArchitecture GetArchitecture();
}

实现此接口的类型:

  • Controller
  • System
  • Model
  • Command
  • Query
  • Event 处理器

作用: 所有实现此接口的类型都能够获取其所属的架构实例,从而访问架构提供的各种能力。

ICanSetArchitecture

定义可以设置架构实例的能力。

接口定义:

public interface ICanSetArchitecture
{
    void SetArchitecture(IArchitecture architecture);
}

实现此接口的类型:

  • Command
  • Query

作用: 在 Command 和 Query 执行前,框架会自动调用 SetArchitecture 方法注入架构实例,使其能够访问 Model、System 等组件。

接口关系图

IBelongToArchitecture (属于架构)
    ↓ 被继承
    ├── ICanGetModel (可获取 Model)
    ├── ICanGetSystem (可获取 System)
    ├── ICanGetUtility (可获取 Utility)
    ├── ICanSendCommand (可发送 Command)
    ├── ICanSendEvent (可发送 Event)
    ├── ICanSendQuery (可发送 Query)
    └── ICanRegisterEvent (可注册 Event)

ICanSetArchitecture (可设置架构)
    ↓ 被继承
    ├── ICommand (命令接口)
    └── IQuery<T> (查询接口)

使用场景

1. Controller 实现 IBelongToArchitecture

// Controller 通过实现 IBelongToArchitecture 获得架构访问能力
public partial class PlayerController : Node, IController
{
    // 实现 IBelongToArchitecture 接口
    public IArchitecture GetArchitecture() => GameArchitecture.Interface;
    
    public override void _Ready()
    {
        // 因为实现了 IBelongToArchitecture所以可以使用扩展方法
        var playerModel = this.GetModel<PlayerModel>();
        this.SendCommand(new InitPlayerCommand());
        this.RegisterEvent<PlayerDiedEvent>(OnPlayerDied);
    }
    
    private void OnPlayerDied(PlayerDiedEvent e)
    {
        GD.Print("Player died!");
    }
}

2. Command 实现 ICanSetArchitecture

// Command 实现 ICanSetArchitecture框架会自动注入架构
public class BuyItemCommand : AbstractCommand
{
    public string ItemId { get; set; }
    
    protected override void OnExecute()
    {
        // 框架已经通过 SetArchitecture 注入了架构实例
        // 所以这里可以直接使用 this.GetModel
        var playerModel = this.GetModel<PlayerModel>();
        var shopModel = this.GetModel<ShopModel>();
        
        int price = shopModel.GetItemPrice(ItemId);
        if (playerModel.Gold.Value >= price)
        {
            playerModel.Gold.Value -= price;
            this.SendCommand(new AddItemCommand { ItemId = ItemId });
        }
    }
}

3. 自定义组件遵循规则

// 自定义管理器遵循框架规则
public class SaveManager : IBelongToArchitecture
{
    private IArchitecture _architecture;
    
    public SaveManager(IArchitecture architecture)
    {
        _architecture = architecture;
    }
    
    public IArchitecture GetArchitecture() => _architecture;
    
    public void SaveGame()
    {
        // 因为实现了 IBelongToArchitecture可以使用扩展方法
        var playerModel = this.GetModel<PlayerModel>();
        var saveData = new SaveData
        {
            PlayerName = playerModel.Name.Value,
            Level = playerModel.Level.Value,
            Gold = playerModel.Gold.Value
        };
        
        // 保存逻辑...
    }
}

规则约束

1. 组件注册规则

public class GameArchitecture : Architecture<GameArchitecture>
{
    protected override void Init()
    {
        // ✅ 正确Model/System/Utility 自动获得架构引用
        this.RegisterModel<PlayerModel>(new PlayerModel());
        this.RegisterSystem<CombatSystem>(new CombatSystem());
        this.RegisterUtility<StorageUtility>(new StorageUtility());
    }
}

// Model 继承 AbstractModelAbstractModel 实现了 IBelongToArchitecture
public class PlayerModel : AbstractModel
{
    // 无需手动实现 GetArchitecture基类已实现
    protected override void OnInit()
    {
        // 可以直接使用架构能力
        this.SendEvent(new PlayerModelInitializedEvent());
    }
}

2. Command/Query 自动注入规则

// Controller 中发送 Command
public class ShopUI : Control, IController
{
    public IArchitecture GetArchitecture() => GameArchitecture.Interface;
    
    private void OnBuyButtonPressed()
    {
        var command = new BuyItemCommand { ItemId = "sword_01" };
        
        // SendCommand 内部会自动调用 command.SetArchitecture(this.GetArchitecture())
        this.SendCommand(command);
    }
}

// Command 执行时已经有了架构引用
public class BuyItemCommand : AbstractCommand
{
    public string ItemId { get; set; }
    
    protected override void OnExecute()
    {
        // 此时 GetArchitecture() 已经可用
        var model = this.GetModel<ShopModel>();
    }
}

设计模式

1. 依赖注入模式

Rule 接口体现了依赖注入DI的思想

// 接口定义了"需要什么"
public interface IBelongToArchitecture
{
    IArchitecture GetArchitecture();
}

// 框架负责"提供什么"
public static class CanSendExtensions
{
    public static void SendCommand<T>(this ICanSendCommand self, T command) 
        where T : ICommand
    {
        // 自动注入架构依赖
        command.SetArchitecture(self.GetArchitecture());
        command.Execute();
    }
}

2. 接口隔离原则ISP

Rule 接口遵循接口隔离原则,每个接口职责单一:

// ❌ 不好的设计:一个大接口包含所有能力
public interface IBigInterface
{
    IArchitecture GetArchitecture();
    void SetArchitecture(IArchitecture architecture);
    T GetModel<T>() where T : class, IModel;
    T GetSystem<T>() where T : class, ISystem;
    void SendCommand<T>(T command) where T : ICommand;
    // ... 更多方法
}

// ✅ 好的设计:小接口组合
public interface IBelongToArchitecture { ... }  // 只负责获取架构
public interface ICanSetArchitecture { ... }    // 只负责设置架构
public interface ICanGetModel { ... }           // 只负责获取 Model
public interface ICanSendCommand { ... }        // 只负责发送 Command

3. 组合优于继承

通过接口组合实现不同能力:

// Controller 需要获取 Model 和发送 Command
public interface IController : ICanGetModel, ICanGetSystem, ICanSendCommand, 
    ICanSendQuery, ICanRegisterEvent
{
}

// Command 需要设置架构和获取 Model/System
public interface ICommand : ICanSetArchitecture, ICanGetModel, ICanGetSystem, 
    ICanSendEvent, ICanSendQuery
{
}

// System 只需要获取其他组件
public interface ISystem : ICanGetModel, ICanGetUtility, ICanGetSystem, 
    ICanRegisterEvent, ICanSendEvent, ICanSendQuery
{
}

扩展规则

自定义规则接口

// 定义新的规则接口
public interface ICanAccessDatabase : IBelongToArchitecture
{
}

// 提供扩展方法
public static class CanAccessDatabaseExtensions
{
    public static DatabaseUtility GetDatabase(this ICanAccessDatabase self)
    {
        return self.GetArchitecture().GetUtility<DatabaseUtility>();
    }
}

// 让特定组件实现这个接口
public class DatabaseCommand : AbstractCommand, ICanAccessDatabase
{
    protected override void OnExecute()
    {
        var db = this.GetDatabase();
        // 使用数据库...
    }
}

最佳实践

  1. 遵循既有规则 - 优先使用框架提供的规则接口
  2. 不要绕过规则 - 不要直接存储架构引用,使用接口获取
  3. 接口组合 - 通过实现多个小接口获得所需能力
  4. 扩展规则 - 需要新能力时,定义新的规则接口
  5. 保持一致 - 自定义组件也应遵循相同的规则体系

相关包

  • architecture - 定义 IArchitecture 接口
  • command - Command 实现 ICanSetArchitecture
  • query - Query 实现 ICanSetArchitecture
  • controller - Controller 实现 IBelongToArchitecture
  • system - System 实现 IBelongToArchitecture
  • model - Model 实现 IBelongToArchitecture
  • extensions - 基于规则接口提供扩展方法