diff --git a/.idea/.idea.GFramework/.idea/icon.png b/.idea/.idea.GFramework/.idea/icon.png new file mode 100644 index 0000000..93b56cc Binary files /dev/null and b/.idea/.idea.GFramework/.idea/icon.png differ diff --git a/docs/zh-CN/core/rule.md b/docs/zh-CN/core/rule.md index f5a2df2..28b4c44 100644 --- a/docs/zh-CN/core/rule.md +++ b/docs/zh-CN/core/rule.md @@ -2,138 +2,280 @@ ## 概述 -Rule 包定义了框架的核心规则接口,这些接口规定了框架各个组件之间的关系和约束。所有框架组件都需要遵循这些规则接口。 +Rule 包定义了框架的核心规则接口 `IContextAware`,这是所有框架组件的基础。通过这个接口,框架实现了统一的上下文管理和能力访问机制。所有框架组件(Command、Query、Model、System)都实现此接口,并通过扩展方法获得访问架构服务的能力。 -## 核心接口 +## 核心接口:IContextAware -### IContextAware - -标记接口,表示该类型可以感知架构上下文。 +`IContextAware` 是框架的核心规则接口,定义了上下文的设置和获取能力。 **接口定义:** ```csharp public interface IContextAware { + /// + /// 设置架构上下文 + /// + /// 架构上下文对象,用于提供架构级别的服务和功能访问 void SetContext(IArchitectureContext context); + + /// + /// 获取架构上下文 + /// + /// 当前的架构上下文对象 IArchitectureContext GetContext(); } ``` +**作用:** + +- `SetContext()` - 框架在初始化组件时调用此方法,注入架构上下文 +- `GetContext()` - 组件通过此方法获取上下文,进而访问所有架构服务 + **实现此接口的类型:** -- System -- Query -- Model -- Command -- 以及其他需要感知架构上下文的组件 +- `AbstractCommand` / `AbstractAsyncCommand` - 命令基类 +- `AbstractQuery` - 查询基类 +- `AbstractModel` - 模型基类 +- `AbstractSystem` - 系统基类 +- 以及其他需要感知架构上下文的自定义组件 -**作用:** -所有实现此接口的类型都能够获取其所属的架构上下文实例,从而访问架构提供的各种能力。 +## 基类实现:ContextAwareBase -## 核心类 +`ContextAwareBase` 是实现 `IContextAware` 的标准基类,为所有需要感知架构上下文的类提供基础实现。 -### [`ContextAwareBase`](./rule.md) - -上下文感知基类,实现了 IContextAware 接口,为需要感知架构上下文的类提供基础实现。 - -**使用方式:** +**类定义:** ```csharp public abstract class ContextAwareBase : IContextAware { + /// + /// 获取当前实例的架构上下文 + /// protected IArchitectureContext? Context { get; set; } - + + /// + /// 设置架构上下文的实现方法,由框架调用 + /// void IContextAware.SetContext(IArchitectureContext context) { Context = context; OnContextReady(); // 上下文准备好后调用此方法 } - + + /// + /// 获取架构上下文 + /// IArchitectureContext IContextAware.GetContext() { Context ??= GameContext.GetFirstArchitectureContext(); return Context; } - - protected virtual void OnContextReady() // 子类可以重写此方法进行初始化 + + /// + /// 当上下文准备就绪时调用的虚方法,子类可以重写此方法来执行上下文相关的初始化逻辑 + /// + protected virtual void OnContextReady() { } } ``` -## 接口关系图 +**关键特性:** -``` -IContextAware (上下文感知接口) - ↓ 被继承于 - ├── AbstractSystem (抽象系统基类) - ├── AbstractQuery (抽象查询基类) - ├── AbstractModel (抽象模型基类) - └── AbstractCommand (抽象命令基类) -``` +- `Context` 属性 - 存储架构上下文的引用 +- `OnContextReady()` 钩子 - 在上下文设置完成后调用,用于初始化逻辑 +- 自动回退机制 - 如果上下文未被显式设置,会自动从 `GameContext.GetFirstArchitectureContext()` 获取 -## 使用场景 +## 扩展方法:框架能力的来源 -### 1. Component 继承 ContextAwareBase +所有框架能力都通过 `ContextAwareExtensions` 类的扩展方法提供。这种设计使得 `IContextAware` 接口保持简洁,同时能够灵活地添加新能力。 + +### 获取架构组件 ```csharp -// 组件通过继承 ContextAwareBase 获得架构上下文访问能力 -public partial class PlayerController : Node, IController -{ - // 不再需要手动实现 IContextAware,基类已处理 - // 可以直接使用扩展方法 - public override void _Ready() - { - var playerModel = this.GetModel(); - this.SendCommand(new InitPlayerCommand()); - this.RegisterEvent(OnPlayerDied); - } - - private void OnPlayerDied(PlayerDiedEvent e) - { - GD.Print("Player died!"); - } -} +// 获取指定类型的模型 +public static TModel? GetModel(this IContextAware contextAware) + where TModel : class, IModel + +// 获取指定类型的系统 +public static TSystem? GetSystem(this IContextAware contextAware) + where TSystem : class, ISystem + +// 获取指定类型的工具 +public static TUtility? GetUtility(this IContextAware contextAware) + where TUtility : class, IUtility + +// 获取指定类型的服务 +public static TService? GetService(this IContextAware contextAware) + where TService : class ``` -### 2. Command 继承 AbstractCommand (IContextAware) +### 发送命令 ```csharp -// Command 继承 AbstractCommand,自动成为 IContextAware -public class BuyItemCommand : AbstractCommand +// 发送无返回值的命令 +public static void SendCommand(this IContextAware contextAware, ICommand command) + +// 发送有返回值的命令 +public static TResult SendCommand(this IContextAware contextAware, + ICommand command) + +// 异步发送无返回值的命令 +public static async Task SendCommandAsync(this IContextAware contextAware, + IAsyncCommand command) + +// 异步发送有返回值的命令 +public static async Task SendCommandAsync(this IContextAware contextAware, + IAsyncCommand command) +``` + +### 发送查询 + +```csharp +// 发送查询并获取结果 +public static TResult SendQuery(this IContextAware contextAware, + IQuery query) +``` + +### 事件系统 + +```csharp +// 注册事件处理器 +public static IUnRegister RegisterEvent(this IContextAware contextAware, + Action handler) + +// 取消事件注册 +public static void UnRegisterEvent(this IContextAware contextAware, + Action onEvent) + +// 发送无参数的事件 +public static void SendEvent(this IContextAware contextAware) + where TEvent : new() + +// 发送具体的事件实例 +public static void SendEvent(this IContextAware contextAware, TEvent e) + where TEvent : class +``` + +### 环境访问 + +```csharp +// 获取环境对象(泛型版本) +public static T? GetEnvironment(this IContextAware contextAware) + where T : class + +// 获取环境对象 +public static IEnvironment GetEnvironment(this IContextAware contextAware) +``` + +## 框架组件如何使用 IContextAware + +### Command 和 AsyncCommand + +所有命令都继承自 `AbstractCommand` 或 `AbstractAsyncCommand`,这些基类实现了 `IContextAware`。 + +```csharp +public class BuyItemCommand : AbstractCommand { - public string ItemId { get; set; } - - protected override void OnExecute() + protected override bool OnExecute() { - // 框架或上下文系统会自动注入 IArchitectureContext - // 所以这里可以直接使用 this.GetModel + // 通过扩展方法访问 Model var playerModel = this.GetModel(); var shopModel = this.GetModel(); - - int price = shopModel.GetItemPrice(ItemId); - if (playerModel.Gold.Value >= price) + + // 业务逻辑 + if (playerModel.Gold.Value >= Input.Price) { - playerModel.Gold.Value -= price; - this.SendCommand(new AddItemCommand { ItemId = ItemId }); + playerModel.Gold.Value -= Input.Price; + // 发送其他命令 + this.SendCommand(new AddItemCommand { ItemId = Input.ItemId }); + return true; } + return false; } } ``` -### 3. 自定义组件遵循规则 +### Query + +所有查询都继承自 `AbstractQuery`,实现了 `IContextAware`。 + +```csharp +public class GetPlayerLevelQuery : AbstractQuery +{ + public override int OnQuery() + { + var playerModel = this.GetModel(); + return playerModel.Level.Value; + } +} +``` + +### Model + +所有模型都继承自 `AbstractModel`,实现了 `IContextAware`。 + +```csharp +public class PlayerModel : AbstractModel +{ + public ReactiveProperty Level { get; } = new(1); + public ReactiveProperty Gold { get; } = new(0); + + protected override void OnContextReady() + { + // 模型初始化时的逻辑 + Console.WriteLine("PlayerModel initialized"); + } +} +``` + +### System + +所有系统都继承自 `AbstractSystem`,实现了 `IContextAware`。 + +```csharp +public class CombatSystem : AbstractSystem +{ + protected override void OnInit() + { + // 注册事件监听 + this.RegisterEvent(OnPlayerAttack); + this.RegisterEvent(OnEnemyDefeated); + } + + private void OnPlayerAttack(PlayerAttackEvent e) + { + var playerModel = this.GetModel(); + var combatModel = this.GetModel(); + + // 处理攻击逻辑 + combatModel.ApplyDamage(e.Damage); + } + + private void OnEnemyDefeated(EnemyDefeatedEvent e) + { + var playerModel = this.GetModel(); + playerModel.Gold.Value += e.RewardGold; + } +} +``` + +## 自定义组件使用 IContextAware + +任何自定义类都可以继承 `ContextAwareBase` 来获得架构上下文访问能力。 ```csharp -// 自定义管理器遵循框架规则,继承 ContextAwareBase public class SaveManager : ContextAwareBase { - // 不再需要手动构造函数传参,上下文由框架注入 - // protected override void OnContextReady() 可用于初始化 - + protected override void OnContextReady() + { + // 上下文准备好后的初始化 + Console.WriteLine("SaveManager initialized"); + } + public void SaveGame() { - // 因为继承了 ContextAwareBase,可以使用扩展方法 var playerModel = this.GetModel(); var saveData = new SaveData { @@ -141,182 +283,69 @@ public class SaveManager : ContextAwareBase Level = playerModel.Level.Value, Gold = playerModel.Gold.Value }; - // 保存逻辑... } -} -``` -## 规则约束 - -### 1. 组件注册规则 - -```csharp -public class GameArchitecture : Architecture -{ - protected override void Init() + public void LoadGame() { - // Model/System/Utility 自动获得架构引用 - this.RegisterModel(new PlayerModel()); - this.RegisterSystem(new CombatSystem()); - this.RegisterUtility(new StorageUtility()); + var playerModel = this.GetModel(); + // 加载逻辑... } } ``` -### 2. Command/Query 自动注入规则 +## 上下文注入机制 + +### 自动注入流程 + +1. **组件创建** - 框架创建 Command、Query、Model、System 等组件 +2. **上下文注入** - 框架调用组件的 `SetContext()` 方法,传入 `IArchitectureContext` +3. **初始化回调** - `ContextAwareBase` 在 `SetContext()` 中调用 `OnContextReady()` 钩子 +4. **能力访问** - 组件现在可以通过扩展方法访问所有架构服务 + +### 回退机制 + +如果组件的上下文未被显式设置,`GetContext()` 会自动尝试从 `GameContext.GetFirstArchitectureContext()` 获取。这提供了一个安全的回退机制。 ```csharp -// Controller 中发送 Command -public class ShopUI : Control, IController +IArchitectureContext IContextAware.GetContext() { - 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(); - } + Context ??= GameContext.GetFirstArchitectureContext(); + return Context; } ``` -## 设计模式 +## 设计优势 -### 1. 依赖注入模式 +### 1. 简洁性 -Rule 接口体现了依赖注入(DI)的思想: +框架只定义了一个核心接口 `IContextAware`,包含两个方法。所有其他能力都通过扩展方法提供,使得接口定义保持简洁易懂。 -```csharp -// 接口定义了"需要什么" -public interface IContextAware -{ - void SetContext(IArchitectureContext context); - IArchitectureContext GetContext(); -} +### 2. 灵活性 -// 框架负责"提供什么" -/// -/// 发送一个事件 -/// -/// 命令执行结果类型 -/// 实现 IContextAware 接口的对象 -/// 要发送的命令 -/// 命令执行结果 -/// 当 contextAware 或 command 为 null 时抛出 -public static TResult SendCommand(this IContextAware contextAware, ICommand command) -{ - ArgumentNullException.ThrowIfNull(contextAware); - ArgumentNullException.ThrowIfNull(command); +扩展方法可以在不修改接口的情况下添加新能力。需要新功能时,只需添加新的扩展方法,无需修改 `IContextAware` 接口。 - var context = contextAware.GetContext(); - return context.SendCommand(command); -} -``` +### 3. 一致性 -### 2. 接口隔离原则(ISP) +所有框架组件使用相同的方式访问架构服务,通过 `IContextAware` 接口和扩展方法。这提供了统一的编程体验。 -Rule 接口遵循接口隔离原则,每个接口职责单一: +### 4. 可扩展性 -```csharp -// ❌ 不好的设计:一个大接口包含所有能力 -public interface IBigInterface -{ - void SetContext(IArchitectureContext context); - IArchitectureContext GetContext(); - T GetModel() where T : class, IModel; - T GetSystem() where T : class, ISystem; - void SendCommand(T command) where T : ICommand; - // ... 更多方法 -} - -// ✅ 好的设计:小接口组合 -public interface IContextAware { ... } // 只负责上下文的设置与获取 -public interface ICanGetModel { ... } // 只负责获取 Model -public interface ICanSendCommand { ... } // 只负责发送 Command -``` - -### 3. 组合优于继承 - -通过接口组合实现不同能力: - -```csharp -// Controller 需要获取 Model 和发送 Command -public interface IController : ICanGetModel, ICanGetSystem, ICanSendCommand, - ICanSendQuery, ICanRegisterEvent -{ -} - -// Command 需要上下文感知和获取 Model/System -public interface ICommand : IContextAware, ICanGetModel, ICanGetSystem, - ICanSendEvent, ICanSendQuery -{ -} - -// System 只需要获取其他组件 -public interface ISystem : IContextAware, ICanGetModel, ICanGetUtility, ICanGetSystem, - ICanRegisterEvent, ICanSendEvent, ICanSendQuery -{ -} -``` - -## 扩展规则 - -### 自定义规则接口 - -```csharp -// 定义新的规则接口 -public interface ICanAccessDatabase : IBelongToArchitecture -{ -} - -// 提供扩展方法 -public static class CanAccessDatabaseExtensions -{ - public static DatabaseUtility GetDatabase(this ICanAccessDatabase self) - { - return self.GetArchitecture().GetUtility(); - } -} - -// 让特定组件实现这个接口 -public class DatabaseCommand : AbstractCommand, ICanAccessDatabase -{ - protected override void OnExecute() - { - var db = this.GetDatabase(); - // 使用数据库... - } -} -``` +自定义组件可以轻松继承 `ContextAwareBase` 并使用所有扩展方法,与框架组件保持一致的设计。 ## 最佳实践 -1. **遵循既有规则** - 优先使用框架提供的规则接口 -2. **不要绕过规则** - 不要直接存储架构引用,使用接口获取 -3. **接口组合** - 通过实现多个小接口获得所需能力 -4. **扩展规则** - 需要新能力时,定义新的规则接口 -5. **保持一致** - 自定义组件也应遵循相同的规则体系 +1. **继承 ContextAwareBase** - 自定义组件应继承 `ContextAwareBase` 而不是直接实现 `IContextAware` +2. **使用 OnContextReady()** - 在 `OnContextReady()` 中进行初始化,而不是在构造函数中 +3. **使用扩展方法** - 通过扩展方法访问架构服务,不要手动存储 `IArchitectureContext` 引用 +4. **避免循环依赖** - 在设计系统和模型时,避免创建循环依赖关系 +5. **遵循单一职责** - 每个组件应该有明确的职责,不要让一个组件做太多事情 ## 相关包 -- [`architecture`](./architecture.md) - 定义 IArchitectureContext 接口 -- [`command`](./command.md) - Command 继承 AbstractCommand (IContextAware) -- [`query`](./query.md) - Query 继承 AbstractQuery (IContextAware) -- **Controller** - Controller 实现 ICanSendCommand 等接口(接口定义在 Core.Abstractions 中) -- [`system`](./system.md) - System 继承 AbstractSystem (IContextAware) -- [`model`](./model.md) - Model 继承 AbstractModel (IContextAware) -- [`extensions`](./extensions.md) - 基于规则接口提供扩展方法 \ No newline at end of file +- [`architecture`](./architecture.md) - 定义 `IArchitectureContext` 接口 +- [`command`](./command.md) - Command 继承 `AbstractCommand` (实现 `IContextAware`) +- [`query`](./query.md) - Query 继承 `AbstractQuery` (实现 `IContextAware`) +- [`model`](./model.md) - Model 继承 `AbstractModel` (实现 `IContextAware`) +- [`system`](./system.md) - System 继承 `AbstractSystem` (实现 `IContextAware`) +- [`extensions`](./extensions.md) - 提供 `ContextAwareExtensions` 扩展方法 \ No newline at end of file