docs(core): 更新命令系统文档并移除控制器独立文档

- 移除 controller.md 文件,将控制器相关内容整合到其他文档中
- 重构 command.md 文档,更新命令基类的类型参数设计
- 添加新的命令基类 AbstractCommand<TInput> 和 AbstractCommand<TInput, TResult>
- 更新命令使用示例,采用输入参数对象替代构造函数参数
- 优化事件注册相关代码示例,移除 Godot 特定的生命周期方法
- 更新依赖注入容器文档,明确 Register 方法的泛型特性
- 添加模型异步初始化功能说明和相关接口介绍
- 重构查询系统文档,统一采用输入参数对象的设计模式
- 更新架构生命周期枚举值,使用更准确的阶段名称
- 添加 GitHub Actions 工作流配置,集成 LLM 准备的文档索引功能
This commit is contained in:
GeWuYou 2026-02-12 13:13:07 +08:00
parent aa0a9f7ab6
commit 93b25a19f7
18 changed files with 2720 additions and 693 deletions

View File

@ -67,6 +67,12 @@ jobs:
working-directory: docs
run: bun run build
# 生成 LLM 索引文件
- name: Make docs LLM ready
uses: demodrive-ai/llms-txt-action@v1
with:
docs-path: docs/.vitepress/dist
# 上传构建产物作为 Pages 部署工件
- name: Upload Pages Artifact
uses: actions/upload-pages-artifact@v3

3
.gitignore vendored
View File

@ -5,4 +5,5 @@ riderModule.iml
/_ReSharper.Caches/
GFramework.sln.DotSettings.user
.idea/
opencode.json
.opencode.json
.claude/

View File

@ -82,7 +82,6 @@ export default defineConfig({
{ text: '工具类', link: '/zh-CN/core/utility' },
{ text: '模型层', link: '/zh-CN/core/model' },
{ text: '系统层', link: '/zh-CN/core/system' },
{ text: '控制器', link: '/zh-CN/core/controller' },
{ text: '规则系统', link: '/zh-CN/core/rule' },
{ text: '环境接口', link: '/zh-CN/core/environment' }
]

View File

@ -0,0 +1,411 @@
# API 参考文档
本文档提供 GFramework 各模块的完整 API 参考。
## 核心命名空间
### GFramework.Core.architecture
核心架构命名空间,包含所有基础组件。
#### 主要类型
| 类型 | 说明 |
|--------------------|--------|
| `Architecture` | 应用架构基类 |
| `AbstractModel` | 数据模型基类 |
| `AbstractSystem` | 业务系统基类 |
| `AbstractCommand` | 命令基类 |
| `AbstractQuery<T>` | 查询基类 |
| `IController` | 控制器接口 |
| `IUtility` | 工具类接口 |
### GFramework.Core.events
事件系统命名空间。
#### 主要类型
| 类型 | 说明 |
|-------------------|----------|
| `IEvent` | 事件接口 |
| `IEventSystem` | 事件系统接口 |
| `TypeEventSystem` | 类型安全事件系统 |
### GFramework.Core.property
属性系统命名空间。
#### 主要类型
| 类型 | 说明 |
|-----------------------|--------|
| `BindableProperty<T>` | 可绑定属性 |
| `IUnRegister` | 注销接口 |
| `IUnRegisterList` | 注销列表接口 |
### GFramework.Core.ioc
IoC 容器命名空间。
#### 主要类型
| 类型 | 说明 |
|--------------|------|
| `IContainer` | 容器接口 |
| `Container` | 容器实现 |
### GFramework.Core.pool
对象池命名空间。
#### 主要类型
| 类型 | 说明 |
|------------------|-------|
| `IObjectPool<T>` | 对象池接口 |
| `ObjectPool<T>` | 对象池实现 |
## 常用 API
### Architecture
```csharp
public abstract class Architecture : IBelongToArchitecture
{
// 初始化架构
public void Initialize();
// 销毁架构
public void Destroy();
// 注册模型
public void RegisterModel<T>(T model) where T : IModel;
// 获取模型
public T GetModel<T>() where T : IModel;
// 注册系统
public void RegisterSystem<T>(T system) where T : ISystem;
// 获取系统
public T GetSystem<T>() where T : ISystem;
// 注册工具
public void RegisterUtility<T>(T utility) where T : IUtility;
// 获取工具
public T GetUt>() where T : IUtility;
// 发送命令
public void SendCommand<T>(T command) where T : ICommand;
// 发送查询
public TResult SendQuery<TQuery, TResult>(TQuery query)
where TQuery : IQuery<TResult>;
// 发送事件
public void SendEvent<T>(T e) where T : IEvent;
}
```
### AbstractModel
```csharp
public abstract class AbstractModel : IBelongToArchitecture
{
// 初始化模型
protected abstract void OnInit();
// 销毁模型
protected virtual void OnDestroy();
// 获取架构
public IArchitecture GetArchitecture();
// 发送事件
protected void SendEvent<T>(T e) where T : IEvent;
// 获取模型
protected T GetModel<T>() where T : IModel;
// 获取系统
protected T GetSystem<T>() where T : ISystem;
// 获取工具
protected T GetUtility<T>() where T : IUtility;
}
```
### AbstractSystem
```csharp
public abstract class AbstractSystem : IBelongToArchitecture
{
// 初始化系统
protected abstract void OnInit();
// 销毁系统
protected virtual void OnDestroy();
// 获取架构
public IArchitecture GetArchitecture();
// 发送事件
protected void SendEvent<T>(T e) where T : IEvent;
// 注册事件
protected IUnRegister RegisterEvent<T>(Action<T> onEvent)
where T : IEvent;
// 获取模型
protected T GetModel<T>() where T : IModel;
// 获取系统
protected T GetSystem<T>() where T : ISystem;
// 获取工具
protected T GetUtility<T>() where T : IUtility;
}
```
### AbstractCommand
```csharp
public abstract class AbstractCommand : IBelongToArchitecture
{
// 执行命令
public void Execute();
// 命令实现
protected abstract void OnDo();
// 获取架构
public IArchitecture GetArchitecture();
// 发送事件
protected void SendEvent<T>(T e) where T : IEvent;
// 获取模型
protected T GetModel<T>() where T : IModel;
// 获取系统
protected T GetSystem<T>() where T : ISystem;
// 获取工具
protected T GetUtility<T>() where T : IUtility;
}
```
### AbstractQuery<T>
```csharp
public abstract class AbstractQuery<T> : IBelongToArchitecture
{
// 执行查询
public T Do();
// 查询实现
protected abstract T OnDo();
// 获取架构
public IArchitecture GetArchitecture();
// 获取模型
protected T GetModel<T>() where T : IModel;
// 获取系统
protected T GetSystem<T>() where T : ISystem;
// 获取工具
protected T GetUtility<T>() where T : IUtility;
}
```
### BindableProperty<T>
```csharp
public class BindableProperty<T>
{
// 构造函数
public BindableProperty(T initialValue = default);
// 获取或设置值
public T Value { get; set; }
// 注册监听器
public IUnRegister Register(Action<T> onValueChanged);
// 注册监听器(包含初始值)
public IUnRegister RegisterWithInitValue(Action<T> onValueChanged);
// 获取当前值
public T GetValue();
// 设置值
public void SetValue(T newValue);
}
```
## 扩展方法
### 架构扩展
```csharp
// 发送命令
public static void SendCommand<T>(this IBelongToArchitecture self, T command)
where T : ICommand;
// 发送查询
public static TResult SendQuery<TQuery, TResult>(
this IBelongToArchitecture self, TQuery query)
where TQuery : IQuery<TResult>;
// 发送事件
public static void SendEvent<T>(this IBelongToArchitecture self, T e)
where T : IEvent;
// 获取模型
public static T GetModel<T>(this IBelongToArchitecture self)
where T : IModel;
// 获取系统
public static T GetSystem<T>(this IBelongToArchitecture self)
where T : ISystem;
// 获取工具
public static T GetUtility<T>(this IBelongToArchitecture self)
where T : IUtility;
// 注册事件
public static IUnRegister RegisterEvent<T>(
this IBelongToArchitecture self, Action<T> onEvent)
where T : IEvent;
```
### 属性扩展
```csharp
// 添加到注销列表
public static IUnRegister AddToUnregisterList(
this IUnRegister self, IUnRegisterList list);
// 注销所有
public static void UnRegisterAll(this IUnRegisterList self);
```
## 游戏模块 API
### GFramework.Game
游戏业务扩展模块。
#### 主要类型
| 类型 | 说明 |
|---------------|--------|
| `GameSetting` | 游戏设置 |
| `GameState` | 游戏状态 |
| `IGameModule` | 游戏模块接口 |
## Godot 集成 API
### GFramework.Godot
Godot 引擎集成模块。
#### 主要类型
| 类型 | 说明 |
|------------------|------------|
| `GodotNode` | Godot 节点扩展 |
| `GodotCoroutine` | Godot 协程 |
| `GodotSignal` | Godot 信号 |
## 源码生成器
### GFramework.SourceGenerators
自动代码生成工具。
#### 支持的生成器
| 生成器 | 说明 |
|--------------------|---------|
| `LoggingGenerator` | 日志生成器 |
| `EnumGenerator` | 枚举扩展生成器 |
| `RuleGenerator` | 规则生成器 |
## 常见用法示例
### 创建架构
```csharp
public class MyArchitecture : Architecture
{
protected override void Init()
{
RegisterModel(new PlayerModel());
RegisterSystem(new PlayerSystem());
RegisterUtility(new StorageUtility());
}
}
// 使用
var arch = new MyArchitecture();
arch.Initialize();
```
### 发送命令
```csharp
public class AttackCommand : AbstractCommand
{
public int Damage { get; set; }
protected override void OnDo()
{
var player = this.GetModel<PlayerModel>();
this.SendEvent(new AttackEvent { Damage = Damage });
}
}
// 使用
arch.SendCommand(new AttackCommand { Damage = 10 });
```
### 发送查询
```csharp
public class GetPlayerHealthQuery : AbstractQuery<int>
{
protected override int OnDo()
{
return this.GetModel<PlayerModel>().Health.Value;
}
}
// 使用
var health = arch.SendQuery(new GetPlayerHealthQuery());
```
### 监听事件
```csharp
public class PlayerSystem : AbstractSystem
{
protected override void OnInit()
{
this.RegisterEvent<PlayerDiedEvent>(OnPlayerDied);
}
private void OnPlayerDied(PlayerDiedEvent e)
{
Console.WriteLine("Player died!");
}
}
```
---
更多详情请查看各模块的详细文档。

View File

@ -0,0 +1,483 @@
# 最佳实践
本文档总结了使用 GFramework 的最佳实践和设计模式。
## 架构设计
### 1. 清晰的职责分离
**原则**:每一层都有明确的职责,不要混淆。
```csharp
// ✅ 正确的职责分离
public class PlayerModel : AbstractModel
{
// Model只存储数据
public BindableProperty<int> Health { get; } = new(100);
public BindableProperty<int> Score { get; } = new(0);
}
public class CombatSystem : AbstractSystem
{
// System处理业务逻辑
protected override void OnInit()
{
this.RegisterEvent<AttackEvent>(OnAttack);
}
private void OnAttack(AttackEvent e)
{
var player = this.GetModel<PlayerModel>();
player.Health.Value -= e.Damage;
}
}
public class PlayerController : IController
{
// Controller连接 UI 和逻辑
public void Initialize()
{
var player = _architecture.GetModel<PlayerModel>();
player.Health.RegisterWithInitValue(OnHealthChanged);
}
private void OnHealthChanged(int health)
{
UpdateHealthDisplay(health);
}
}
```
### 2. 事件驱动设计
**原则**:使用事件解耦组件,避免直接调用。
```csharp
// ❌ 紧耦合
public class SystemA : AbstractSystem
{
private void OnEvent(EventA e)
{
var systemB = this.GetSystem<SystemB>();
systemB.DoSomething(); // 直接调用
}
}
// ✅ 松耦合
public class SystemA : AbstractSystem
{
private void OnEvent(EventA e)
{
this.SendEvent(new EventB()); // 发送事件
}
}
public class SystemB : AbstractSystem
{
protected override void OnInit()
{
this.RegisterEvent<EventB>(OnEventB);
}
}
```
### 3. 命令查询分离
**原则**明确区分修改状态Command和查询状态Query
```csharp
// ✅ 正确的 CQRS
public class MovePlayerCommand : AbstractCommand
{
public Vector2 Direction { get; set; }
protected override void OnDo()
{
// 修改状态
this.SendEvent(new PlayerMovedEvent { Direction = Direction });
}
}
public class GetPlayerPositionQuery : AbstractQuery<Vector2>
{
protected override Vector2 OnDo()
{
// 只查询,不修改
return this.GetModel<PlayerModel>().Position.Value;
}
}
```
## 代码组织
### 1. 项目结构
```
GameProject/
├── Models/
│ ├── PlayerModel.cs
│ ├── GameStateModel.cs
│ └── InventoryModel.cs
├── Systems/
│ ├── CombatSystem.cs
│ ├── InventorySystem.cs
│ └── GameLogicSystem.cs
├── Commands/
│ ├── AttackCommand.cs
│ ├── MoveCommand.cs
│ └── UseItemCommand.cs
├── Queries/
│ ├── GetPlayerHealthQuery.cs
│ └── GetInventoryItemsQuery.cs
├── Events/
│ ├── PlayerDiedEvent.cs
│ ├── ItemUsedEvent.cs
│ └── EnemyDamagedEvent.cs
├── Controllers/
│ ├── PlayerController.cs
│ └── UIController.cs
├── Utilities/
│ ├── StorageUtility.cs
│ └── MathUtility.cs
└── GameArchitecture.cs
```
### 2. 命名规范
```csharp
// Models使用 Model 后缀
public class PlayerModel : AbstractModel { }
public class GameStateModel : AbstractModel { }
// Systems使用 System 后缀
public class CombatSystem : AbstractSystem { }
public class InventorySystem : AbstractSystem { }
// Commands使用 Command 后缀
public class AttackCommand : AbstractCommand { }
public class MoveCommand : AbstractCommand { }
// Queries使用 Query 后缀
public class GetPlayerHealthQuery : AbstractQuery<int> { }
public class GetInventoryItemsQuery : AbstractQuery<List<Item>> { }
// Events使用 Event 后缀
public class PlayerDiedEvent : IEvent { }
public class ItemUsedEvent : IEvent { }
// Controllers使用 Controller 后缀
public class PlayerController : IController { }
// Utilities使用 Utility 后缀
public class StorageUtility : IUtility { }
```
## 内存管理
### 1. 正确的注销管理
```csharp
public class MyController : IController
{
private IUnRegisterList _unregisterList = new UnRegisterList();
public void Initialize()
{
var model = _architecture.GetModel<PlayerModel>();
// 注册事件并添加到注销列表
this.RegisterEvent<PlayerDiedEvent>(OnPlayerDied)
.AddToUnregisterList(_unregisterList);
// 注册属性监听并添加到注销列表
model.Health.Register(OnHealthChanged)
.AddToUnregisterList(_unregisterList);
}
public void Cleanup()
{
// 统一注销所有监听器
_unregisterList.UnRegisterAll();
}
private void OnPlayerDied(PlayerDiedEvent e) { }
private void OnHealthChanged(int health) { }
}
```
### 2. 生命周期管理
```csharp
public class GameManager
{
private GameArchitecture _architecture;
public void StartGame()
{
_architecture = new GameArchitecture();
_architecture.Initialize();
}
public void EndGame()
{
// 销毁架构,自动清理所有组件
_architecture.Destroy();
_architecture = null;
}
}
```
## 性能优化
### 1. 缓存组件引用
```csharp
// ❌ 低效:每次都查询
public void Update()
{
var model = _architecture.GetModel<PlayerModel>();
model.Health.Value -= 1;
}
// ✅ 高效:缓存引用
private PlayerModel _playerModel;
public void Initialize()
{
_playerModel = _architecture.GetModel<PlayerModel>();
}
public void Update()
{
_playerModel.Health.Value -= 1;
}
```
### 2. 避免频繁的事件创建
```csharp
// ❌ 低效:每帧创建新事件
public void Update()
{
this.SendEvent(new UpdateEvent()); // 频繁分配内存
}
// ✅ 高效:复用事件或使用对象池
private UpdateEvent _updateEvent = new UpdateEvent();
public void Update()
{
this.SendEvent(_updateEvent);
}
```
### 3. 异步处理重操作
```csharp
public class LoadDataCommand : AbstractCommand
{
protected override async void OnDo()
{
// 异步加载数据,不阻塞主线程
var data = await LoadDataAsync();
this.SendEvent(new DataLoadedEvent { Data = data });
}
private async Task<Data> LoadDataAsync()
{
return await Task.Run(() =>
{
// 耗时操作
return new Data();
});
}
}
```
## 测试
### 1. 单元测试
```csharp
[TestFixture]
public class CombatSystemTests
{
private GameArchitecture _architecture;
private PlayerModel _playerModel;
[SetUp]
public void Setup()
{
_architecture = new TestArchitecture();
_architecture.Initialize();
_playerModel = _architecture.GetModel<PlayerModel>();
}
[TearDown]
public void Teardown()
{
_architecture.Destroy();
}
[Test]
public void PlayerTakeDamage_ReducesHealth()
{
_playerModel.Health.Value = 100;
_architecture.SendEvent(new DamageEvent { Amount = 10 });
Assert.AreEqual(90, _playerModel.Health.Value);
}
[Test]
public void PlayerDies_WhenHealthReachesZero()
{
_playerModel.Health.Value = 10;
_architecture.SendEvent(new DamageEvent { Amount = 10 });
Assert.AreEqual(0, _playerModel.Health.Value);
}
}
```
### 2. 集成测试
```csharp
[TestFixture]
public class GameFlowTests
{
private GameArchitecture _architecture;
[SetUp]
public void Setup()
{
_architecture = new GameArchitecture();
_architecture.Initialize();
}
[Test]
public void CompleteGameFlow()
{
// 初始化
var player = _architecture.GetModel<PlayerModel>();
Assert.AreEqual(100, player.Health.Value);
// 执行操作
_architecture.SendCommand(new AttackCommand { Damage = 20 });
// 验证结果
Assert.AreEqual(80, player.Health.Value);
}
}
```
## 文档
### 1. 代码注释
```csharp
/// <summary>
/// 玩家模型,存储玩家的所有状态数据
/// </summary>
public class PlayerModel : AbstractModel
{
/// <summary>
/// 玩家的生命值,使用 BindableProperty 实现响应式更新
/// </summary>
public BindableProperty<int> Health { get; } = new(100);
protected override void OnInit()
{
// 监听生命值变化,当生命值为 0 时发送死亡事件
Health.Register(hp =>
{
if (hp <= 0)
this.SendEvent(new PlayerDiedEvent());
});
}
}
```
### 2. 架构文档
为你的项目编写架构文档,说明:
- 主要的 Model、System、Command、Query
- 关键事件流
- 组件间的通信方式
- 扩展点和插件机制
## 常见陷阱
### 1. 在 Model 中包含业务逻辑
```csharp
// ❌ 错误
public class PlayerModel : AbstractModel
{
public void TakeDamage(int damage)
{
Health.Value -= damage;
if (Health.Value <= 0)
Die();
}
}
// ✅ 正确
public class CombatSystem : AbstractSystem
{
private void OnDamage(DamageEvent e)
{
var player = this.GetModel<PlayerModel>();
player.Health.Value -= e.Amount;
}
}
```
### 2. 忘记注销监听器
```csharp
// ❌ 错误:可能导致内存泄漏
public void Initialize()
{
this.RegisterEvent<Event1>(OnEvent1); // 未注销
}
// ✅ 正确
private IUnRegisterList _unregisterList = new UnRegisterList();
public void Initialize()
{
this.RegisterEvent<Event1>(OnEvent1)
.AddToUnregisterList(_unregisterList);
}
public void Cleanup()
{
_unregisterList.UnRegisterAll();
}
```
### 3. 直接调用其他系统
```csharp
// ❌ 错误:紧耦合
public class SystemA : AbstractSystem
{
private void OnEvent(EventA e)
{
var systemB = this.GetSystem<SystemB>();
systemB.DoSomething();
}
}
// ✅ 正确:使用事件解耦
public class SystemA : AbstractSystem
{
private void OnEvent(EventA e)
{
this.SendEvent(new EventB());
}
}
```
---
遵循这些最佳实践将帮助你构建可维护、高效、可扩展的应用程序。

View File

@ -0,0 +1,443 @@
# 异步初始化指南
## 概述
异步初始化是 GFramework 中的一个重要特性,允许 Architecture、Model、System 等组件在初始化时执行异步操作。这对于需要加载大量资源、进行网络请求或其他耗时操作的场景特别有用。
## 核心接口
### IAsyncInitializable
异步初始化接口,定义了异步初始化的契约。
**核心方法:**
```csharp
Task InitializeAsync(); // 异步初始化方法
```
**实现者:**
- `Architecture` - 架构支持异步初始化
- `AbstractModel` - Model 可以实现异步初始化
- `AbstractSystem` - System 可以实现异步初始化
- `AbstractUtility` - Utility 可以实现异步初始化
## 异步 Architecture
### 基本使用
```csharp
public class GameArchitecture : Architecture
{
protected override void Init()
{
// 同步初始化逻辑
RegisterModel(new PlayerModel());
RegisterSystem(new CombatSystem());
}
}
// 异步初始化架构
var architecture = new GameArchitecture();
await architecture.InitializeAsync();
// 等待架构就绪
await architecture.WaitUntilReadyAsync();
```
### 初始化流程
异步初始化遵循以下流程:
1. 创建架构实例
2. 调用 `InitializeAsync()` 方法
3. 执行同步初始化(`Init()` 方法)
4. 按顺序异步初始化各个阶段:
- 工具异步初始化BeforeUtilityInit → AfterUtilityInit
- 模型异步初始化BeforeModelInit → AfterModelInit
- 系统异步初始化BeforeSystemInit → AfterSystemInit
5. 进入 Ready 阶段
6. 返回 Task 完成
##
### 定义异步 Model
```csharp
public class ConfigModel : AbstractModel, IAsyncInitializable
{
public BindableProperty<GameConfig> Config { get; } = new(null);
protected override void OnInit()
{
// 同步初始化逻辑
Console.WriteLine("ConfigModel sync init");
}
public async Task InitializeAsync()
{
// 异步加载配置
var storage = this.GetUtility<IStorageUtility>();
var config = await storage.LoadConfigAsync();
Config.Value = config;
Console.WriteLine("ConfigModel async init completed");
this.SendEvent(new ConfigLoadedEvent { Config = config });
}
}
public class PlayerDataModel : AbstractModel, IAsyncInitializable
{
public BindableProperty<PlayerData> PlayerData { get; } = new(null);
protected override void OnInit()
{
// 同步初始化逻辑
}
public async Task InitializeAsync()
{
// 异步加载玩家数据
var storage = this.GetUtility<IStorageUtility>();
var playerId = this.GetContext().Environment.Get<string>("PlayerId");
var playerData = await storage.LoadPlayerDataAsync(playerId);
PlayerData.Value = playerData;
}
}
```
### 在架构中使用异步 Model
```csharp
public class GameArchitecture : Architecture
{
protected override void Init()
{
// 注册异步 Model
RegisterModel(new ConfigModel());
RegisterModel(new PlayerDataModel());
RegisterModel(new PlayerModel());
// 注册 System
RegisterSystem(new CombatSystem());
}
}
// 使用
var architecture = new GameArchitecture();
await architecture.InitializeAsync();
```
## 异步 System
### 定义异步 System
```csharp
public class DataLoadSystem : AbstractSystem, IAsyncInitializable
{
private GameData _gameData;
protected override void OnInit()
{
// 同步初始化逻辑
this.RegisterEvent<GameStartedEvent>(OnGameStarted);
}
public async Task InitializeAsync()
{
// 异步加载游戏数据
var storage = this.GetUtility<IStorageUtility>();
_gameData = await storage.LoadGameDataAsync();
Console.WriteLine("Game data loaded");
this.SendEvent(new GameDataLoadedEvent { Data = _gameData });
}
private void OnGameStarted(GameStartedEvent e)
{
Console.WriteLine($"Game started with data version: {_gameData.Version}");
}
}
public class ResourceLoadSystem : AbstractSystem, IAsyncInitializable
{
private Dictionary<string, Resource> _resources = new();
protected override void OnInit()
{
// 同步初始化逻辑
}
public async Task InitializeAsync()
{
// 异步加载资源
var resourceManager = this.GetUtility<IResourceManager>();
_resources = await resourceManager.LoadAllResourcesAsync();
Console.WriteLine($"Loaded {_resources.Count} resources");
}
}
```
## 异步 Utility
### 定义异步 Utility
```csharp
public class DatabaseUtility : IUtility, IAsyncInitializable
{
private Database _database;
public void Init()
{
// 同步初始化逻辑
}
public async Task InitializeAsync()
{
// 异步连接数据库
_database = new Database();
await _database.ConnectAsync("connection_string");
Console.WriteLine("Database connected");
}
public async Task<T> QueryAsync<T>(string sql)
{
return await _database.QueryAsync<T>(sql);
}
}
```
## 完整示例
### 场景:游戏启动流程
```csharp
// 1. 定义各个异步组件
public class ConfigModel : AbstractModel, IAsyncInitializable
{
public BindableProperty<GameConfig> Config { get; } = new(null);
protected override void OnInit() { }
public async Task InitializeAsync()
{
var storage = this.GetUtility<IStorageUtility>();
Config.Value = await storage.LoadConfigAsync();
}
}
public class PlayerModel : AbstractModel, IAsyncInitializable
{
public BindableProperty<PlayerData> PlayerData { get; } = new(null);
protected override void OnInit() { }
public async Task InitializeAsync()
{
var storage = this.GetUtility<IStorageUtility>();
var playerId = this.GetContext().Environment.Get<string>("PlayerId");
PlayerData.Value = await storage.LoadPlayerDataAsync(playerId);
}
}
public class ResourceLoadSystem : AbstractSystem, IAsyncInitializable
{
private Dictionary<string, Resource> _resources = new();
protected override void OnInit()
{
this.RegisterEvent<GameStartedEvent>(OnGameStarted);
}
public async Task InitializeAsync()
{
var resourceManager = this.GetUtility<IResourceManager>();
_resources = await resourceManager.LoadAllResourcesAsync();
}
private void OnGameStarted(GameStartedEvent e)
{
Console.WriteLine("Game started with all resources loaded");
}
}
// 2. 定义架构
public class GameArchitecture : Architecture
{
protected override void Init()
{
RegisterModel(new ConfigModel());
RegisterModel(new PlayerModel());
RegisterSystem(new ResourceLoadSystem());
RegisterSystem(new CombatSystem());
}
}
// 3. 使用架构
public class GameBootstrapper
{
public async Task StartGameAsync()
{
var architecture = new GameArchitecture();
// 异步初始化架构
await architecture.InitializeAsync();
// 等待架构就绪
await architecture.WaitUntilReadyAsync();
Console.WriteLine("Game is ready!");
// 发送游戏启动事件
architecture.SendEvent(new GameStartedEvent());
}
}
```
## 同步 vs 异步初始化
### 同步初始化
```csharp
var architecture = new GameArchitecture();
architecture.Initialize(); // 阻塞等待初始化完成
// 立即可以使用架构
var playerModel = architecture.GetModel<PlayerModel>();
```
**特点:**
- 阻塞式,等待初始化完成
- 适用于简单场景或控制台应用
- 初始化失败时抛出异常
### 异步初始化
```csharp
var architecture = new GameArchitecture();
await architecture.InitializeAsync(); // 非阻塞等待
// 初始化完成后可以使用架构
var playerModel = architecture.GetModel<PlayerModel>();
```
**特点:**
- 非阻塞式,不会阻塞主线程
- 支持异步组件初始化
- 适用于需要加载大量资源的场景
- 初始化失败时抛出异常
## 最佳实践
### 1. 合理划分同步和异步初始化
```csharp
public class MyModel : AbstractModel, IAsyncInitializable
{
protected override void OnInit()
{
// 同步初始化:快速的初始化逻辑
// - 注册事件监听
// - 初始化本地数据结构
// - 设置默认值
}
public async Task InitializeAsync()
{
// 异步初始化:耗时的初始化逻辑
// - 加载文件
// - 网络请求
// - 数据库查询
}
}
```
### 2. 处理异步初始化异常
```csharp
public async Task StartGameAsync()
{
var architecture = new GameArchitecture();
try
{
await architecture.InitializeAsync();
}
catch (Exception ex)
{
Console.WriteLine($"Initialization failed: {ex.Message}");
// 处理初始化失败
}
}
```
### 3. 显示加载进度
```csharp
public class ProgressTrackingArchitecture : Architecture
{
public event Action<float> OnProgressChanged;
protected override void Init()
{
RegisterModel(new ConfigModel());
RegisterModel(new PlayerModel());
RegisterSystem(new ResourceLoadSystem());
}
public async Task InitializeAsyncWithProgress()
{
OnProgressChanged?.Invoke(0.0f);
// 初始化各个阶段
await InitializeAsync();
OnProgressChanged?.Invoke(1.0f);
}
}
// 使用
var architecture = new ProgressTrackingArchitecture();
architecture.OnProgressChanged += progress =>
{
Console.WriteLine($"Loading: {progress * 100}%");
};
await architecture.InitializeAsyncWithProgress();
```
### 4. 超时控制
```csharp
public async Task StartGameWithTimeoutAsync()
{
var architecture = new GameArchitecture();
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
try
{
var initTask = architecture.InitializeAsync();
await initTask.ConfigureAwait(false);
}
catch (OperationCanceledException)
{
Console.WriteLine("Initialization timeout");
}
}
```
## 相关包
- [`architecture`](./architecture.md) - 架构核心,支持异步初始化
- [`model`](./model.md) - Model 可以实现异步初始化
- [`system`](./system.md) - System 可以实现异步初始化
- [`utility`](./utility.md) - Utility 可以实现异步初始化
---
**许可证**Apache 2.0

View File

@ -44,31 +44,14 @@ protected abstract void OnExecute(); // 抽象执行方法,由子类实
**使用示例:**
```csharp
// 定义一个开始游戏的命令
public class StartGameCommand : AbstractCommand
// 定义一个无返回值的基础命令
public class SimpleCommand : AbstractCommand
{
private readonly int _levelId;
private readonly string _playerName;
public StartGameCommand(int levelId, string playerName)
{
_levelId = levelId;
_playerName = playerName;
}
protected override void OnExecute()
{
// 获取需要的模型
var playerModel = this.GetModel<PlayerModel>();
var gameModel = this.GetModel<GameModel>();
// 执行业务逻辑
playerModel.PlayerName.Value = _playerName;
gameModel.CurrentLevel.Value = _levelId;
gameModel.GameState.Value = GameState.Playing;
// 发送事件通知其他模块
this.SendEvent(new GameStartedEvent());
playerModel.Health.Value = playerModel.MaxHealth.Value;
this.SendEvent(new PlayerHealthRestoredEvent());
}
}
@ -77,17 +60,16 @@ public class GameController : IController
{
public IArchitecture GetArchitecture() => GameArchitecture.Interface;
public void OnStartButtonClicked()
public void OnRestoreHealthButtonClicked()
{
// 发送命令实例
this.SendCommand(new StartGameCommand(1, "Player1"));
this.SendCommand(new SimpleCommand());
}
}
```
### AbstractCommandWithResult`<TResult>`
### AbstractCommand`<TResult>`
带返回值命令的抽象基类,同样继承自 ContextAwareBase
无输入参数但带返回值命令基类。
**核心方法:**
@ -99,49 +81,28 @@ protected abstract TResult OnExecute(); // 抽象执行方法,由子类实
**使用示例:**
```csharp
// 定义一个计算伤害的命令
public class CalculateDamageCommand : AbstractCommandWithResult<int>
// 定义一个无输入但有返回值的命令
public class GetPlayerHealthQuery : AbstractCommand<int>
{
private readonly int _attackerAttackPower;
private readonly int _defenderDefense;
public CalculateDamageCommand(int attackerAttackPower, int defenderDefense)
{
_attackerAttackPower = attackerAttackPower;
_defenderDefense = defenderDefense;
}
protected override int OnExecute()
{
// 获取游戏配置
var config = this.GetModel<GameConfigModel>();
// 计算最终伤害
var baseDamage = _attackerAttackPower - _defenderDefense;
var finalDamage = Math.Max(1, baseDamage * config.DamageMultiplier);
return (int)finalDamage;
var playerModel = this.GetModel<PlayerModel>();
return playerModel.Health.Value;
}
}
// 使用带返回值的命令
public class CombatSystem : AbstractSystem
// 使用命令
public class UISystem : AbstractSystem
{
protected override void OnInit() { }
public void Attack(Character attacker, Character defender)
protected override void OnInit()
{
// 发送命令并获取返回值
var damage = this.SendCommand(new CalculateDamageCommand(
attacker.AttackPower,
defender.Defense
));
this.RegisterEvent<UpdateUIEvent>(OnUpdateUI);
}
// 应用伤害
defender.Health -= damage;
// 发送伤害事件
this.SendEvent(new DamageDealtEvent(attacker, defender, damage));
private void OnUpdateUI(UpdateUIEvent e)
{
var health = this.SendCommand(new GetPlayerHealthQuery());
Console.WriteLine($"Player health: {health}");
}
}
```
@ -195,45 +156,167 @@ var damage = commandBus.Send(new CalculateDamageCommand(100, 50));
框架提供了多种命令基类以满足不同需求:
### AbstractCommand
### AbstractCommand`<TInput>`
最基础的无返回值命令类
带输入参数的无返回值命令类。通过 `ICommandInput` 接口传递参数。
### AbstractCommandWithResult`<TResult>`
带返回值的命令基类
### AbstractCommandWithInput`<TInput>`
带输入参数的无返回值命令类
### AbstractCommandWithInputAndResult`<TInput, TResult>`
既带输入参数又带返回值的命令类
### AbstractAsyncCommand
支持异步执行的命令基类
### AbstractAsyncCommandWithResult`<TResult>`
支持异步执行的带返回值命令基类
**核心方法:**
```csharp
// 异步命令示例
public class LoadSaveDataCommand : AbstractAsyncCommandWithResult<SaveData>
void ICommand.Execute(); // 实现 ICommand 接口
protected abstract void OnExecute(TInput input); // 抽象执行方法,接收输入参数
```
**使用示例:**
```csharp
// 定义输入对象
public class StartGameInput : ICommandInput
{
private readonly string _saveSlot;
public int LevelId { get; set; }
public string PlayerName { get; set; }
}
public LoadSaveDataCommand(string saveSlot)
// 定义命令
public class StartGameCommand : AbstractCommand<StartGameInput>
{
protected override void OnExecute(StartGameInput input)
{
_saveSlot = saveSlot;
}
var playerModel = this.GetModel<PlayerModel>();
var gameModel = this.GetModel<GameModel>();
protected override async Task<SaveData> OnExecuteAsync()
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()
{
var input = new StartGameInput { LevelId = 1, PlayerName = "Player1" };
this.SendCommand(new StartGameCommand { Input = input });
}
}
```
### AbstractCommand`<TInput, TResult>`
既带输入参数又带返回值的命令类。
**核心方法:**
```csharp
TResult ICommand<TResult>.Execute(); // 实现 ICommand<TResult> 接口
protected abstract TResult OnExecute(TInput input); // 抽象执行方法,接收输入参数
```
**使用示例:**
```csharp
// 定义输入对象
public class CalculateDamageInput : ICommandInput
{
public int AttackerAttackPower { get; set; }
public int DefenderDefense { get; set; }
}
// 定义命令
public class CalculateDamageCommand : AbstractCommand<CalculateDamageInput, int>
{
protected override int OnExecute(CalculateDamageInput 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 input = new CalculateDamageInput
{
AttackerAttackPower = attacker.AttackPower,
DefenderDefense = defender.Defense
};
var damage = this.SendCommand(new CalculateDamageCommand { Input = input });
defender.Health -= damage;
this.SendEvent(new DamageDealtEvent(attacker, defender, damage));
}
}
```
### AbstractAsyncCommand`<TInput>`
支持异步执行的带输入参数的无返回值命令基类。
**核心方法:**
```csharp
Task IAsyncCommand.ExecuteAsync(); // 实现异步命令接口
protected abstract Task OnExecuteAsync(TInput input); // 抽象异步执行方法
```
### AbstractAsyncCommand`<TInput, TResult>`
支持异步执行的既带输入参数又带返回值的命令基类。
**核心方法:**
```csharp
Task<TResult> IAsyncCommand<TResult>.ExecuteAsync(); // 实现异步命令接口
protected abstract Task<TResult> OnExecuteAsync(TInput input); // 抽象异步执行方法
```
**使用示例:**
```csharp
// 定义输入对象
public class LoadSaveDataInput : ICommandInput
{
public string SaveSlot { get; set; }
}
// 定义异步命令
public class LoadSaveDataCommand : AbstractAsyncCommand<LoadSaveDataInput, SaveData>
{
protected override async Task<SaveData> OnExecuteAsync(LoadSaveDataInput input)
{
var storage = this.GetUtility<IStorageUtility>();
return await storage.LoadSaveDataAsync(_saveSlot);
return await storage.LoadSaveDataAsync(input.SaveSlot);
}
}
// 使用异步命令
public class SaveSystem : AbstractSystem
{
protected override void OnInit()
{
this.RegisterEvent<LoadGameRequestEvent>(OnLoadGameRequest);
}
private async void OnLoadGameRequest(LoadGameRequestEvent e)
{
var input = new LoadSaveDataInput { SaveSlot = e.SaveSlot };
var saveData = await this.SendCommandAsync(new LoadSaveDataCommand { Input = input });
if (saveData != null)
{
this.SendEvent(new GameLoadedEvent { SaveData = saveData });
}
}
}
```

490
docs/zh-CN/core/context.md Normal file
View File

@ -0,0 +1,490 @@
# Context 上下文指南
## 概述
Context上下文是 GFramework 中的核心概念,提供了对架构服务的统一访问入口。通过 Context组件可以访问事件总线、命令总线、查询总线、IoC
容器等核心服务。
## 核心接口
### IArchitectureContext
架构上下文接口,定义了对架构服务的访问契约。
**核心属性:**
```csharp
IEventBus EventBus { get; } // 事件总线
ICommandBus CommandBus { get; } // 命令总线
IQueryBus QueryBus { get; } // 查询总线
IIocContainer Container { get; } // IoC 容器
IEnvironment Environment { get; } // 环境配置
IArchitectureConfiguration Configuration { get; } // 架构配置
ILogger Logger { get; } // 日志系统
```
## 核心类
### ArchitectureContext
架构上下文的完整实现。
**使用示例:**
```csharp
// 通过架构获取上下文
var context = architecture.Context;
// 访问各个服务
var eventBus = context.EventBus;
var commandBus = context.CommandBus;
var queryBus = context.QueryBus;
var container = context.Container;
var environment = context.Environment;
var logger = context.Logger;
```
### GameContext
游戏上下文类,管理架构类型与上下文实例的映射关系。
**核心方法:**
```csharp
// 绑定架构类型到上下文
static void Bind<TArchitecture>(IArchitectureContext context)
where TArchitecture : IArchitecture;
// 获取架构类型对应的上下文
static IArchitectureContext GetContext<TArchitecture>()
where TArchitecture : IArchitecture;
// 解绑架构类型
static void Unbind<TArchitecture>()
where TArchitecture : IArchitecture;
```
## 在组件中使用 Context
### 在 Model 中使用
```csharp
public class PlayerModel : AbstractModel
{
public BindableProperty<int> Health { get; } = new(100);
protected override void OnInit()
{
// 通过 Context 访问事件总线
var context = this.GetContext();
var eventBus = context.EventBus;
// 监听生命值变化
Health.Register(hp =>
{
if (hp <= 0)
{
// 发送事件
eventBus.Send(new PlayerDiedEvent());
}
});
}
}
```
### 在 System 中使用
```csharp
public class CombatSystem : AbstractSystem
{
protected override void OnInit()
{
// 通过 Context 访问各个服务
var context = this.GetContext();
var eventBus = context.EventBus;
var commandBus = context.CommandBus;
var container = context.Container;
// 注册事件监听
eventBus.Register<EnemyAttackEvent>(OnEnemyAttack);
}
private void OnEnemyAttack(EnemyAttackEvent e)
{
var context = this.GetContext();
var playerModel = context.Container.Get<PlayerModel>();
// 处理伤害
playerModel.Health.Value -= e.Damage;
}
}
```
### 在 Command 中使用
```csharp
public class StartGameCommand : AbstractCommand
{
protected override void OnExecute()
{
// 通过 Context 访问服务
var context = this.GetContext();
var container = context.Container;
var eventBus = context.EventBus;
var playerModel = container.Get<PlayerModel>();
playerModel.Health.Value = playerModel.MaxHealth.Value;
eventBus.Send(new GameStartedEvent());
}
}
```
### 在 Query 中使用
```csharp
public class GetPlayerHealthQuery : AbstractQuery<int>
{
protected override int OnDo()
{
// 通过 Context 访问容器
var context = this.GetContext();
var playerModel = context.Container.Get<PlayerModel>();
return playerModel.Health.Value;
}
}
```
## GameContext 的使用
### 绑定架构到 GameContext
```csharp
public class GameArchitecture : Architecture
{
protected override void Init()
{
// 注册组件
RegisterModel(new PlayerModel());
RegisterSystem(new CombatSystem());
}
}
// 在应用启动时绑定
var architecture = new GameArchitecture();
await architecture.InitializeAsync();
// 绑定架构到 GameContext
GameContext.Bind<GameArchitecture>(architecture.Context);
```
### 从 GameContext 获取上下文
```csharp
// 在任何地方获取架构上下文
var context = GameContext.GetContext<GameArchitecture>();
// 访问服务
var playerModel = context.Container.Get<PlayerModel>();
var eventBus = context.EventBus;
```
### 使用 GameContext 的扩展方法
```csharp
// 通过扩展方法简化访问
public static class GameContextExtensions
{
public static T GetModel<T>(this IArchitectureContext context)
where T : class, IModel
{
return context.Container.Get<T>();
}
public static T GetSystem<T>(this IArchitectureContext context)
where T : class, ISystem
{
return context.Container.Get<T>();
}
}
// 使用
var context = GameContext.GetContext<GameArchitecture>();
var playerModel = context.GetModel<PlayerModel>();
var combatSystem = context.GetSystem<CombatSystem>();
```
## Context 中的服务
### EventBus - 事件总线
```csharp
var context = architecture.Context;
var eventBus = context.EventBus;
// 注册事件
eventBus.Register<PlayerDiedEvent>(e =>
{
Console.WriteLine("Player died!");
});
// 发送事件
eventBus.Send(new PlayerDiedEvent());
```
### CommandBus - 命令总线
```csharp
var context = architecture.Context;
var commandBus = context.CommandBus;
// 发送命令
commandBus.Send(new StartGameCommand());
// 发送带返回值的命令
var damage = commandBus.Send(new CalculateDamageCommand { Input = input });
```
### QueryBus - 查询总线
```csharp
var context = architecture.Context;
var queryBus = context.QueryBus;
// 发送查询
var health = queryBus.Send(new GetPlayerHealthQuery { Input = new EmptyQueryInput() });
```
### Container - IoC 容器
```csharp
var context = architecture.Context;
var container = context.Container;
// 获取已注册的组件
var playerModel = container.Get<PlayerModel>();
var combatSystem = container.Get<CombatSystem>();
// 获取所有实现某接口的组件
var allSystems = container.GetAll<ISystem>();
```
### Environment - 环境配置
```csharp
var context = architecture.Context;
var environment = context.Environment;
// 获取环境值
var gameMode = environment.Get<string>("GameMode");
var maxPlayers = environment.Get<int>("MaxPlayers");
// 安全获取值
if (environment.TryGet<string>("ServerAddress", out var address))
{
Console.WriteLine($"Server: {address}");
}
```
### Logger - 日志系统
```csharp
var context = architecture.Context;
var logger = context.Logger;
// 记录日志
logger.Log("Game started");
logger.LogWarning("Low memory");
logger.LogError("Failed to load resource");
```
## Context 的生命周期
### 创建
Context 在架构初始化时自动创建:
```csharp
var architecture = new GameArchitecture();
// Context 在这里被创建
var context = architecture.Context;
```
### 使用
Context 在架构的整个生命周期中可用:
```csharp
// 初始化期间
await architecture.InitializeAsync();
// Ready 阶段
var context = architecture.Context;
var playerModel = context.Container.Get<PlayerModel>();
// 销毁前
architecture.Destroy();
```
### 销毁
Context 随着架构的销毁而销毁:
```csharp
architecture.Destroy();
// Context 不再可用
```
## 最佳实践
### 1. 通过扩展方法简化访问
```csharp
public static class ContextExtensions
{
public static T GetModel<T>(this IArchitectureContext context)
where T : class, IModel
{
return context.Container.Get<T>();
}
public static T GetSystem<T>(this IArchitectureContext context)
where T : class, ISystem
{
return context.Container.Get<T>();
}
public static void SendCommand(this IArchitectureContext context, ICommand command)
{
context.CommandBus.Send(command);
}
public static TResult SendQuery<TResult>(this IArchitectureContext context, IQuery<TResult> query)
{
return context.QueryBus.Send(query);
}
}
// 使用
var context = architecture.Context;
var playerModel = context.GetModel<PlayerModel>();
context.SendCommand(new StartGameCommand());
```
### 2. 缓存 Context 引用
```csharp
public class GameSystem : AbstractSystem
{
private IArchitectureContext _context;
protected override void OnInit()
{
// 缓存 Context 引用
_context = this.GetContext();
// 后续使用缓存的引用
_context.EventBus.Register<GameStartedEvent>(OnGameStarted);
}
private void OnGameStarted(GameStartedEvent e)
{
var playerModel = _context.Container.Get<PlayerModel>();
}
}
```
### 3. 使用 GameContext 实现全局访问
```csharp
// 在应用启动时绑定
public class GameBootstrapper
{
public async Task StartAsync()
{
var architecture = new GameArchitecture();
await architecture.InitializeAsync();
// 绑定到 GameContext
GameContext.Bind<GameArchitecture>(architecture.Context);
}
}
// 在任何地方访问
public class UIController
{
public void UpdateHealthDisplay()
{
var context = GameContext.GetContext<GameArchitecture>();
var playerModel = context.Container.Get<PlayerModel>();
// 更新 UI
healthText.text = playerModel.Health.Value.ToString();
}
}
```
### 4. 处理 Context 不可用的情况
```csharp
public class SafeGameSystem : AbstractSystem
{
protected override void OnInit()
{
try
{
var context = this.GetContext();
if (context == null)
{
Console.WriteLine("Context not available");
return;
}
var playerModel = context.Container.Get<PlayerModel>();
}
catch (Exception ex)
{
Console.WriteLine($"Error accessing context: {ex.Message}");
}
}
}
```
## Context vs Architecture
### Architecture
- **职责**:管理组件的生命周期
- **作用**:注册、初始化、销毁组件
- **访问**:通过 `GetArchitecture()` 获取
### Context
- **职责**:提供对架构服务的访问
- **作用**:访问事件总线、命令总线、查询总线等
- **访问**:通过 `GetContext()` 获取
```csharp
// Architecture 用于管理
var architecture = GameArchitecture.Interface;
architecture.RegisterModel(new PlayerModel());
// Context 用于访问服务
var context = architecture.Context;
var playerModel = context.Container.Get<PlayerModel>();
```
## 相关包
- [`architecture`](./architecture.md) - 架构核心,创建和管理 Context
- [`ioc`](./ioc.md) - IoC 容器,通过 Context 访问
- [`events`](./events.md) - 事件总线,通过 Context 访问
- [`command`](./command.md) - 命令总线,通过 Context 访问
- [`query`](./query.md) - 查询总线,通过 Context 访问
- [`environment`](./environment.md) - 环境配置,通过 Context 访问
- [`logging`](./logging.md) - 日志系统,通过 Context 访问
---
**许可证**Apache 2.0

View File

@ -1,413 +0,0 @@
# Controller 包使用说明
## 概述
Controller 包定义了控制器Controller的接口规范。控制器是 MVC 架构中的 C 层,负责处理用户交互、协调视图和模型,是连接表现层和业务层的桥梁。
**注意**本框架使用依赖注入模式Controller 通过构造函数或属性注入获取架构实例,而非使用全局单例。
## 核心接口
### [`IController`](./controller.md)
控制器接口,定义了控制器需要实现的所有功能契约。
**继承的能力接口:**
- [`ICanSendCommand`](./command.md) - 可发送命令
- [`ICanGetSystem`](./system.md) - 可获取系统
- [`ICanGetModel`](./model.md) - 可获取模型
- [`ICanRegisterEvent`](./events.md) - 可注册事件
- [`ICanSendQuery`](./query.md) - 可发送查询
- [`ICanGetUtility`](./utility.md) - 可获取工具
**能力说明:**
控制器拥有框架中最全面的能力集合,可以:
1. 发送命令执行业务逻辑
2. 获取系统调用服务
3. 获取模型读写数据
4. 注册事件监听变化
5. 发送查询获取信息
6. 获取工具使用辅助功能
## 使用示例
### 基础控制器实现(依赖注入模式)
```csharp
using GFramework.Core.architecture;
// 通过依赖注入获取架构
public class PlayerController : IController
{
private readonly IArchitecture _architecture;
private readonly IUnRegisterList _unregisterList = new UnRegisterList();
// 通过构造函数注入架构
public PlayerController(IArchitecture architecture)
{
_architecture = architecture;
}
public void Initialize()
{
// 获取模型
var playerModel = _architecture.GetModel<PlayerModel>();
// 监听模型变化
playerModel.Health.RegisterWithInitValue(OnHealthChanged)
.AddToUnregisterList(_unregisterList);
// 注册事件
_architecture.RegisterEvent<PlayerLevelUpEvent>(OnPlayerLevelUp)
.AddToUnregisterList(_unregisterList);
}
// 处理用户输入
public void ProcessInput(double delta)
{
if (Input.IsActionJustPressed("attack"))
{
// 发送命令
_architecture.SendCommand(new AttackCommand());
}
if (Input.IsActionJustPressed("use_item"))
{
// 发送查询
var inventory = _architecture.SendQuery(new GetInventoryQuery());
if (inventory.HasItem("potion"))
{
_architecture.SendCommand(new UseItemCommand("potion"));
}
}
}
private void OnHealthChanged(int newHealth)
{
// 更新 UI 显示
UpdateHealthBar(newHealth);
}
private void OnPlayerLevelUp(PlayerLevelUpEvent e)
{
// 显示升级特效
ShowLevelUpEffect();
}
public void Cleanup()
{
// 清理事件注册
_unregisterList.UnRegisterAll();
}
private void UpdateHealthBar(int health) { /* UI 更新逻辑 */ }
private void ShowLevelUpEffect() { /* 特效逻辑 */ }
}
```
### UI 控制器示例
``csharp
// UI 面板控制器
public class MainMenuController : IController
{
[Inject] private IArchitecture _architecture;
[Inject] private IUISystem _uiSystem;
[Export] private Button _startButton;
[Export] private Button _settingsButton;
[Export] private Button _quitButton;
public void Initialize()
{
// 绑定按钮事件
_startButton.Pressed += OnStartButtonPressed;
_settingsButton.Pressed += OnSettingsButtonPressed;
_quitButton.Pressed += OnQuitButtonPressed;
// 获取模型更新 UI
var gameModel = _architecture.GetModel<GameModel>();
UpdateUI(gameModel);
}
private void OnStartButtonPressed()
{
// 通过命令启动游戏
_architecture.SendCommand<StartGameCommand>();
}
private void OnSettingsButtonPressed()
{
// 查询当前设置
var settings = _architecture.SendQuery(new GetSettingsQuery());
// 打开设置面板
_uiSystem.OpenSettingsPanel(settings);
}
private void OnQuitButtonPressed()
{
// 发送退出命令
_architecture.SendCommand<QuitGameCommand>();
}
private void UpdateUI(GameModel model) { /* UI 更新逻辑 */ }
}
```
### 复杂交互控制器
``csharp
// 战斗控制器
public class CombatController : IController
{
[Inject] protected IArchitecture _architecture;
private IUnRegisterList _unregisterList = new UnRegisterList();
private PlayerModel _playerModel;
private CombatSystem _combatSystem;
[PostConstruct]
public void Init()
{
// 缓存常用引用
_playerModel = _architecture.GetModel<PlayerModel>();
_combatSystem = _architecture.GetSystem<CombatSystem>();
// 注册多个事件
_architecture.RegisterEvent<EnemySpawnedEvent>(OnEnemySpawned)
.AddToUnregisterList(_unregisterList);
_architecture.RegisterEvent<CombatEndedEvent>(OnCombatEnded)
.AddToUnregisterList(_unregisterList);
// 监听模型状态
_playerModel.CombatState.Register(OnCombatStateChanged)
.AddToUnregisterList(_unregisterList);
}
private void OnEnemySpawned(EnemySpawnedEvent e)
{
// 进入战斗状态
_architecture.SendCommand(new EnterCombatCommand(e.Enemy));
}
private void OnCombatEnded(CombatEndedEvent e)
{
if (e.Victory)
{
// 查询奖励
var rewards = _architecture.SendQuery(new CalculateRewardsQuery(e.Enemy));
// 发放奖励
_architecture.SendCommand(new GiveRewardsCommand(rewards));
}
else
{
// 处理失败
_architecture.SendCommand<GameOverCommand>();
}
}
private void OnCombatStateChanged(CombatState state)
{
// 根据战斗状态更新 UI
_architecture.GetSystem<UISystem>().UpdateCombatUI(state);
}
public void Cleanup()
{
_unregisterList.UnRegisterAll();
}
}
```
## 控制器职责
### ✅ 应该做的事
1. **处理用户输入**
- 键盘、鼠标、触摸输入
- UI 按钮点击
- 手势识别
2. **协调视图和模型**
- 监听模型变化更新视图
- 将用户操作转换为命令
3. **管理界面逻辑**
- UI 元素的显示/隐藏
- 动画播放控制
- 视觉反馈
4. **事件监听**
- 注册关心的事件
- 响应事件更新界面
### ❌ 不应该做的事
1. **不包含业务逻辑**
- 业务逻辑应该在 System 中
- 控制器只负责调用和协调
2. **不直接修改模型**
- 应该通过 Command 修改模型
- 避免直接访问 Model 的 setter
3. **不处理复杂计算**
- 复杂计算应该在 Query 或 System 中
- 控制器保持简洁
4. **不保存核心状态**
- 核心状态应该在 Model 中
- 控制器可以保存临时 UI 状态
## 生命周期管理
### 事件注销
``csharp
public class MyController : IController
{
[Inject] private IArchitecture _architecture;
// 使用 UnRegisterList 统一管理
private IUnRegisterList _unregisterList = new UnRegisterList();
public void Initialize()
{
// 所有事件注册都添加到列表
_architecture.RegisterEvent<GameEvent>(OnGameEvent)
.AddToUnregisterList(_unregisterList);
_architecture.GetModel<PlayerModel>().Health.Register(OnHealthChanged)
.AddToUnregisterList(_unregisterList);
}
public void Cleanup()
{
// 统一注销所有事件
_unregisterList.UnRegisterAll();
}
}
```
## 最佳实践
1. **使用依赖注入获取依赖**
- 通过构造函数注入 `IArchitecture`
- 使用 `[Inject]` 属性标记注入字段
2. **保持控制器轻量**
- 复杂逻辑放在 Command、Query、System 中
- 控制器只做协调和转发
3. **合理使用缓存**
- 频繁使用的 Model、System 可以缓存引用
- 平衡性能和内存占用
4. **统一管理事件注销**
- 使用 `IUnRegisterList` 统一管理
- 在 `Cleanup()` 中统一注销
5. **命名规范**
- 控制器类名:`XxxController`
- 使用 `[Inject]` 或构造函数注入获取架构
## 常见模式
### 数据绑定模式
``csharp
public class ScoreController : IController
{
[Inject] private IArchitecture _architecture;
public void Initialize()
{
// 绑定模型数据到 UI
_architecture.GetModel<GameModel>()
.Score
.RegisterWithInitValue(score => UpdateDisplay(score))
.AddToUnregisterList(_unregisterList);
}
private void UpdateDisplay(int score)
{
// 更新分数显示
}
}
```
### 状态机模式
``csharp
public class PlayerStateController : IController
{
[Inject] private IArchitecture _architecture;
private Dictionary<PlayerState, Action> _stateHandlers;
public void Initialize()
{
_stateHandlers = new Dictionary<PlayerState, Action>
{
{ PlayerState.Idle, HandleIdleState },
{ PlayerState.Moving, HandleMovingState },
{ PlayerState.Attacking, HandleAttackingState }
};
_architecture.GetModel<PlayerModel>()
.State
.Register(OnStateChanged)
.AddToUnregisterList(_unregisterList);
}
private void OnStateChanged(PlayerState state)
{
_stateHandlers[state]?.Invoke();
}
}
```
## 与 Godot 集成
在 Godot 项目中,可以使用 GFramework.Godot 提供的扩展:
``csharp
using GFramework.Godot;
public partial class GodotPlayerController : Node, IController
{
[Inject] private IArchitecture _architecture;
public override void _Ready()
{
// 使用 Godot 特定的自动注销扩展
_architecture.RegisterEvent<PlayerDiedEvent>(OnPlayerDied)
.UnRegisterWhenNodeExitTree(this);
_architecture.GetModel<PlayerModel>()
.Health
.RegisterWithInitValue(OnHealthChanged)
.UnRegisterWhenNodeExitTree(this);
}
}
```
## 相关包
- [`architecture`](./architecture.md) - 提供架构访问能力
- [`command`](./command.md) - 控制器发送命令执行业务逻辑
- [`query`](./query.md) - 控制器发送查询获取数据
- [`events`](./events.md) - 控制器注册事件监听变化
- [`model`](./model.md) - 控制器读取模型数据
- [`system`](./system.md) - 控制器调用系统服务
- [`extensions`](./extensions.md) - 提供便捷的扩展方法
- **GFramework.Godot** - Godot 特定的控制器扩展
---
**许可证**: Apache 2.0

View File

@ -90,7 +90,7 @@ public class DefaultEnvironment : EnvironmentBase
### 1. 定义自定义环境
```
```csharp
public class GameEnvironment : EnvironmentBase
{
public override string Name { get; } = "Game";
@ -112,7 +112,7 @@ public class GameEnvironment : EnvironmentBase
### 2. 在架构中使用环境
```
```csharp
public class GameArchitecture : Architecture
{
protected override void Init()
@ -130,7 +130,7 @@ public class GameArchitecture : Architecture
### 3. 使用环境值
```
```csharp
public class NetworkSystem : AbstractSystem
{
private string _serverAddress;
@ -183,7 +183,7 @@ public class NetworkSystem : AbstractSystem
## 错误示例
```
```csharp
// ❌ 错误:获取必需值但不存在
public class BadExampleSystem : AbstractSystem
{

View File

@ -353,13 +353,13 @@ public class CombatSystem : AbstractSystem
### Controller 中注册事件
```csharp
public partial class GameController : Node, IController
public class GameController : IController
{
private IUnRegisterList _unregisterList = new UnRegisterList();
public IArchitecture GetArchitecture() => GameArchitecture.Interface;
public override void _Ready()
public void Initialize()
{
// 注册多个事件
this.RegisterEvent<GameStartedEvent>(OnGameStarted)
@ -389,7 +389,7 @@ public partial class GameController : Node, IController
ShowVictoryScreen(e);
}
public override void _ExitTree()
public void Cleanup()
{
_unregisterList.UnRegisterAll();
}
@ -449,9 +449,11 @@ public class EventBridge : AbstractSystem
### 4. 临时事件监听
```csharp
public class TutorialController : Node, IController
public class TutorialController : IController
{
public override void _Ready()
public IArchitecture GetArchitecture() => GameArchitecture.Interface;
public void Initialize()
{
// 只监听一次
IUnRegister unregister = null;
@ -495,12 +497,12 @@ public class AchievementSystem : AbstractSystem
### 使用 UnRegisterList
```csharp
public class MyController : Node, IController
public class MyController : IController
{
// 统一管理所有注销对象
private IUnRegisterList _unregisterList = new UnRegisterList();
public override void _Ready()
public void Initialize()
{
// 所有注册都添加到列表
this.RegisterEvent<Event1>(OnEvent1)
@ -510,7 +512,7 @@ public class MyController : Node, IController
.AddToUnregisterList(_unregisterList);
}
public override void _ExitTree()
public void Cleanup()
{
// 一次性注销所有
_unregisterList.UnRegisterAll();
@ -518,17 +520,6 @@ public class MyController : Node, IController
}
```
### 使用 Godot 节点生命周期
```csharp
public override void _Ready()
{
// 当节点退出场景树时自动注销
this.RegisterEvent<GameEvent>(OnGameEvent)
.UnRegisterWhenNodeExitTree(this);
}
```
## 最佳实践
1. **事件命名规范**
@ -553,7 +544,7 @@ public override void _Ready()
5. **注销管理**
- 始终注销事件监听
- 使用 `IUnRegisterList` 批量管理
- 利用 Godot 节点生命周期
- 在适当的生命周期点调用 `Cleanup()`
6. **性能考虑**
- 避免频繁触发的事件(如每帧)

View File

@ -45,7 +45,7 @@
┌─────────────────────────────────────────┐
│ View / UI │ UI 层:用户界面
├─────────────────────────────────────────┤
│ Controller │ 控制层:处理用户输入
│ Controller │ 控制层:连接 UI 和业务逻辑
├─────────────────────────────────────────┤
│ System │ 逻辑层:业务逻辑
├─────────────────────────────────────────┤

View File

@ -38,17 +38,15 @@ public class IocContainer : ContextAwareBase, IIocContainer
```csharp
public void Register<T>(T instance)
public void Register(Type type, object instance)
```
**参数:**
- `instance`: 要注册的实例对象
- `type`: 要注册的类型(重载方法)
**特点:**
- 支持泛型和非泛型注册
- 支持泛型注册
- 自动注册到实例的所有接口类型
- 线程安全操作
- 容器冻结后抛出异常
@ -62,11 +60,10 @@ var container = new IocContainer();
container.Register<IPlayerModel>(new PlayerModel());
container.Register<IGameSystem>(new GameSystem());
container.Register<IStorageUtility>(new StorageUtility());
// 非泛型注册
container.Register(typeof(ICustomService), new CustomService());
```
**注意:** 非泛型的 `Register(Type, object)` 方法是内部方法 `RegisterInternal`,不作为公开 API 使用。
### RegisterSingleton`<T>`
注册单例实例到容器中。一个类型只允许一个实例。
@ -136,35 +133,36 @@ var system2 = container.Get<IUpdateable>(); // 返回 gameSystem
var system3 = container.Get<GameSystem>(); // 返回 gameSystem
```
### RegisterSystem
### RegisterSystemArchitecture 方法)
注册系统实例,将其绑定到其所有实现的接口上
**注意:** `RegisterSystem``Architecture` 类的方法,不是 `IocContainer` 的方法。它用于在架构中注册系统实例。
**方法签名:**
**方法签名(在 Architecture 中)**
```csharp
public void RegisterSystem(ISystem system)
public TSystem RegisterSystem<TSystem>(TSystem system) where TSystem : ISystem
```
**参数:**
- `system`: 系统实例对象
**特点:**
- 专门为 System 设计的注册方法
- 内部调用 `RegisterPlurality`
- 内部调用 `IocContainer.RegisterPlurality`
- 自动处理 System 的生命周期
- 提供语义化的 API
**使用示例:**
```csharp
var container = new IocContainer();
// 注册系统
container.RegisterSystem(new CombatSystem());
container.RegisterSystem(new InventorySystem());
container.RegisterSystem(new QuestSystem());
public class GameArchitecture : Architecture
{
protected override void Init()
{
// 注册系统
RegisterSystem(new CombatSystem());
RegisterSystem(new InventorySystem());
RegisterSystem(new QuestSystem());
}
}
```
### Get`<T>` 和 GetAll`<T>`

View File

@ -61,13 +61,18 @@ public class PlayerModel : AbstractModel
{
switch (phase)
{
case ArchitecturePhase.Initializing:
// 架构初始化阶段的处理
case ArchitecturePhase.BeforeModelInit:
// 模型初始化前的处理
break;
case ArchitecturePhase.AfterModelInit:
// 模型初始化后的处理
break;
case ArchitecturePhase.Ready:
// 架构就绪阶段的处理
break;
// ... 其他阶段处理
case ArchitecturePhase.Destroying:
// 架构销毁阶段的处理
break;
}
}
}
@ -157,7 +162,7 @@ public class GameModel : AbstractModel
{
switch (phase)
{
case ArchitecturePhase.ShuttingDown:
case ArchitecturePhase.Destroying:
// 游戏模型清理工作
break;
default:
@ -167,6 +172,48 @@ public class GameModel : AbstractModel
}
```
## 异步 Model
Model 支持异步初始化,通过实现 `IAsyncInitializable` 接口可以在初始化时执行异步操作。
```csharp
// 异步模型示例
public class ConfigModel : AbstractModel, IAsyncInitializable
{
public BindableProperty<GameConfig> Config { get; } = new(null);
protected override void OnInit()
{
// 同步初始化逻辑
}
public async Task InitializeAsync()
{
// 异步加载配置
var storage = this.GetUtility<IStorageUtility>();
var config = await storage.LoadConfigAsync();
Config.Value = config;
// 配置加载完成后发送事件
this.SendEvent(new ConfigLoadedEvent { Config = config });
}
}
// 在架构中使用异步 Model
public class GameArchitecture : Architecture
{
protected override void Init()
{
RegisterModel(new ConfigModel());
RegisterModel(new PlayerModel());
}
}
// 异步初始化架构
var architecture = new GameArchitecture();
await architecture.InitializeAsync();
```
## 最佳实践
1. **使用 BindableProperty 存储需要监听的数据**
@ -174,6 +221,7 @@ public class GameModel : AbstractModel
3. **复杂计算和业务逻辑放在 System 中**
4. **使用事件通知数据的重要变化**
5. **保持 Model 简单纯粹,只做数据管理**
6. **对于需要异步加载的数据,实现 IAsyncInitializable 接口**
## 相关包

View File

@ -21,27 +21,40 @@ TResult Do(); // 执行查询并返回结果
## 核心类
### AbstractQuery`<TResult>`
### AbstractQuery`<TInput, TResult>`
抽象查询基类,提供了查询的基础实现。
抽象查询基类,提供了查询的基础实现。通过 `IQueryInput` 接口传递参数。
**核心方法:**
```csharp
TResult IQuery<TResult>.Do(); // 实现 IQuery 接口
protected abstract TResult OnDo(); // 抽象查询方法,由子类实现
protected abstract TResult OnDo(TInput input); // 抽象查询方法,接收输入参数
```
**使用方式:**
```csharp
public abstract class AbstractQuery<TResult> : ContextAwareBase, IQuery<TResult>
public abstract class AbstractQuery<TInput, TResult> : ContextAwareBase, IQuery<TResult>
where TInput : IQueryInput
{
public TResult Do() => OnDo(); // 执行查询
protected abstract TResult OnDo(); // 子类实现查询逻辑
public TResult Do() => OnDo(Input); // 执行查询
public TInput Input { get; set; } // 输入参数
protected abstract TResult OnDo(TInput input); // 子类实现查询逻辑
}
```
### AbstractAsyncQuery`<TInput, TResult>`
支持异步执行的查询基类。
**核心方法:**
```csharp
Task<TResult> IAsyncQuery<TResult>.DoAsync(); // 实现异步查询接口
protected abstract Task<TResult> OnDoAsync(TInput input); // 抽象异步查询方法
```
### EmptyQueryInput
空查询输入类,用于表示不需要任何输入参数的查询操作。
@ -83,54 +96,62 @@ public sealed class QueryBus : IQueryBus
### 1. 定义查询
```csharp
// 定义查询输入
public class GetPlayerGoldInput : IQueryInput { }
// 查询玩家金币数量
public class GetPlayerGoldQuery : AbstractQuery<int>
public class GetPlayerGoldQuery : AbstractQuery<GetPlayerGoldInput, int>
{
protected override int OnDo()
protected override int OnDo(GetPlayerGoldInput input)
{
return this.GetModel<PlayerModel>().Gold.Value;
}
}
// 查询玩家是否死亡
public class IsPlayerDeadQuery : AbstractQuery<bool>
// 定义查询输入
public class GetItemCountInput : IQueryInput
{
protected override bool OnDo()
{
return this.GetModel<PlayerModel>().Health.Value <= 0;
}
public string ItemId { get; set; }
}
// 查询背包中指定物品的数量
public class GetItemCountQuery : AbstractQuery<int>
public class GetItemCountQuery : AbstractQuery<GetItemCountInput, int>
{
private readonly string _itemId;
public GetItemCountQuery(string itemId)
{
_itemId = itemId;
}
protected override int OnDo()
protected override int OnDo(GetItemCountInput input)
{
var inventory = this.GetModel<InventoryModel>();
return inventory.GetItemCount(_itemId);
return inventory.GetItemCount(input.ItemId);
}
}
// 定义异步查询输入
public class LoadPlayerDataInput : IQueryInput
{
public string PlayerId { get; set; }
}
// 异步查询玩家数据
public class LoadPlayerDataQuery : AbstractAsyncQuery<LoadPlayerDataInput, PlayerData>
{
protected override async Task<PlayerData> OnDoAsync(LoadPlayerDataInput input)
{
var storage = this.GetUtility<IStorageUtility>();
return await storage.LoadPlayerDataAsync(input.PlayerId);
}
}
```
```
### 2. 发送查询
```csharp
public partial class ShopUI : Control, IController
public class ShopUI : IController
{
[Export] private Button _buyButton;
[Export] private int _itemPrice = 100;
public IArchitecture GetArchitecture() => GameArchitecture.Interface;
public override void _Ready()
public void OnReady()
{
_buyButton.Pressed += OnBuyButtonPressed;
}
@ -138,12 +159,13 @@ public partial class ShopUI : Control, IController
private void OnBuyButtonPressed()
{
// 查询玩家金币
int playerGold = this.SendQuery(new GetPlayerGoldQuery());
var query = new GetPlayerGoldQuery { Input = new GetPlayerGoldInput() };
int playerGold = this.SendQuery(query);
if (playerGold >= _itemPrice)
{
// 发送购买命令
this.SendCommand(new BuyItemCommand("sword_01"));
this.SendCommand(new BuyItemCommand { Input = new BuyItemInput { ItemId = "sword_01" } });
}
else
{
@ -167,15 +189,24 @@ public class CombatSystem : AbstractSystem
private void OnEnemyAttack(EnemyAttackEvent e)
{
// 查询玩家是否已经死亡
bool isDead = this.SendQuery(new IsPlayerDeadQuery());
var query = new IsPlayerDeadQuery { Input = new EmptyQueryInput() };
bool isDead = this.SendQuery(query);
if (!isDead)
{
// 执行伤害逻辑
this.SendCommand(new TakeDamageCommand(e.Damage));
this.SendCommand(new TakeDamageCommand { Input = new TakeDamageInput { Damage = e.Damage } });
}
}
}
public class IsPlayerDeadQuery : AbstractQuery<EmptyQueryInput, bool>
{
protected override bool OnDo(EmptyQueryInput input)
{
return this.GetModel<PlayerModel>().Health.Value <= 0;
}
}
```
```
@ -184,111 +215,105 @@ public class CombatSystem : AbstractSystem
### 1. 带参数的复杂查询
```csharp
// 查询指定范围内的敌人列表
public class GetEnemiesInRangeQuery : AbstractQuery<List<Enemy>>
// 定义查询输入
public class GetEnemiesInRangeInput : IQueryInput
{
private readonly Vector3 _center;
private readonly float _radius;
public Vector3 Center { get; set; }
public float Radius { get; set; }
}
public GetEnemiesInRangeQuery(Vector3 center, float radius)
{
_center = center;
_radius = radius;
}
protected override List<Enemy> OnDo()
// 查询指定范围内的敌人列表
public class GetEnemiesInRangeQuery : AbstractQuery<GetEnemiesInRangeInput, List<Enemy>>
{
protected override List<Enemy> OnDo(GetEnemiesInRangeInput input)
{
var enemySystem = this.GetSystem<EnemySpawnSystem>();
return enemySystem.GetEnemiesInRange(_center, _radius);
return enemySystem.GetEnemiesInRange(input.Center, input.Radius);
}
}
// 使用
var enemies = this.SendQuery(new GetEnemiesInRangeQuery(playerPosition, 10.0f));
var input = new GetEnemiesInRangeInput { Center = playerPosition, Radius = 10.0f };
var query = new GetEnemiesInRangeQuery { Input = input };
var enemies = this.SendQuery(query);
```
### 2. 组合查询
```csharp
// 查询玩家是否可以使用技能
public class CanUseSkillQuery : AbstractQuery<bool>
// 定义查询输入
public class CanUseSkillInput : IQueryInput
{
private readonly string _skillId;
public string SkillId { get; set; }
}
public CanUseSkillQuery(string skillId)
{
_skillId = skillId;
}
protected override bool OnDo()
// 查询玩家是否可以使用技能
public class CanUseSkillQuery : AbstractQuery<CanUseSkillInput, bool>
{
protected override bool OnDo(CanUseSkillInput input)
{
var playerModel = this.GetModel<PlayerModel>();
var skillModel = this.GetModel<SkillModel>();
// 查询技能消耗
var skillCost = this.SendQuery(new GetSkillCostQuery(_skillId));
var skillCostQuery = new GetSkillCostQuery { Input = new GetSkillCostInput { SkillId = input.SkillId } };
var skillCost = this.SendQuery(skillCostQuery);
// 检查是否满足条件
return playerModel.Mana.Value >= skillCost.ManaCost
&& !this.SendQuery(new IsSkillOnCooldownQuery(_skillId));
&& !this.SendQuery(new IsSkillOnCooldownQuery { Input = new IsSkillOnCooldownInput { SkillId = input.SkillId } });
}
}
public class GetSkillCostQuery : AbstractQuery<SkillCost>
public class GetSkillCostInput : IQueryInput
{
private readonly string _skillId;
public GetSkillCostQuery(string skillId)
{
_skillId = skillId;
}
protected override SkillCost OnDo()
{
return this.GetModel<SkillModel>().GetSkillCost(_skillId);
}
public string SkillId { get; set; }
}
public class IsSkillOnCooldownQuery : AbstractQuery<bool>
public class GetSkillCostQuery : AbstractQuery<GetSkillCostInput, SkillCost>
{
private readonly string _skillId;
public IsSkillOnCooldownQuery(string skillId)
protected override SkillCost OnDo(GetSkillCostInput input)
{
_skillId = skillId;
}
protected override bool OnDo()
{
return this.GetModel<SkillModel>().IsOnCooldown(_skillId);
return this.GetModel<SkillModel>().GetSkillCost(input.SkillId);
}
}
public class IsSkillOnCooldownInput : IQueryInput
{
public string SkillId { get; set; }
}
public class IsSkillOnCooldownQuery : AbstractQuery<IsSkillOnCooldownInput, bool>
{
protected override bool OnDo(IsSkillOnCooldownInput input)
{
return this.GetModel<SkillModel>().IsOnCooldown(input.SkillId);
}
}
```
```
### 3. 聚合数据查询
```csharp
// 查询玩家战斗力
public class GetPlayerPowerQuery : AbstractQuery<int>
public class GetPlayerPowerQuery : AbstractQuery<EmptyQueryInput, int>
{
protected override int OnDo()
protected override int OnDo(EmptyQueryInput input)
{
var playerModel = this.GetModel<PlayerModel>();
var equipmentModel = this.GetModel<EquipmentModel>();
int basePower = playerModel.Level.Value * 10;
int equipmentPower = equipmentModel.GetTotalPower();
int buffPower = this.SendQuery(new GetBuffPowerQuery());
int buffPower = this.SendQuery(new GetBuffPowerQuery { Input = new EmptyQueryInput() });
return basePower + equipmentPower + buffPower;
}
}
// 查询玩家详细信息用于UI显示
public class GetPlayerInfoQuery : AbstractQuery<PlayerInfo>
public class GetPlayerInfoQuery : AbstractQuery<EmptyQueryInput, PlayerInfo>
{
protected override PlayerInfo OnDo()
protected override PlayerInfo OnDo(EmptyQueryInput input)
{
var playerModel = this.GetModel<PlayerModel>();
@ -298,8 +323,8 @@ public class GetPlayerInfoQuery : AbstractQuery<PlayerInfo>
Level = playerModel.Level.Value,
Health = playerModel.Health.Value,
MaxHealth = playerModel.MaxHealth.Value,
Gold = this.SendQuery(new GetPlayerGoldQuery()),
Power = this.SendQuery(new GetPlayerPowerQuery())
Gold = this.SendQuery(new GetPlayerGoldQuery { Input = new GetPlayerGoldInput() }),
Power = this.SendQuery(new GetPlayerPowerQuery { Input = new EmptyQueryInput() })
};
}
}
@ -311,37 +336,31 @@ public class GetPlayerInfoQuery : AbstractQuery<PlayerInfo>
// 在 AI System 中查询玩家状态
public class EnemyAISystem : AbstractSystem
{
protected override void OnInit() { }
protected override void OnInit() { }
public void UpdateEnemyBehavior(Enemy enemy)
{
// 查询玩家位置
var playerPos = this.SendQuery(new GetPlayerPositionQuery());
var playerPosQuery = new GetPlayerPositionQuery { Input = new EmptyQueryInput() };
var playerPos = this.SendQuery(playerPosQuery);
// 查询玩家是否在攻击范围内
bool inRange = this.SendQuery(new IsPlayerInRangeQuery
{
Position = enemy.Position,
Range = enemy.AttackRange
});
var inRangeInput = new IsPlayerInRangeInput { Position = enemy.Position, Range = enemy.AttackRange };
bool inRange = this.SendQuery(new IsPlayerInRangeQuery { Input = inRangeInput });
if (inRange)
{
// 查询是否可以攻击
bool canAttack = this.SendQuery(new CanEnemyAttackQuery
{
EnemyId = enemy.Id
});
var canAttackInput = new CanEnemyAttackInput { EnemyId = enemy.Id };
bool canAttack = this.SendQuery(new CanEnemyAttackQuery { Input = canAttackInput });
if (canAttack)
{
this.SendCommand(new EnemyAttackCommand { EnemyId = enemy.Id });
this.SendCommand(new EnemyAttackCommand { Input = new EnemyAttackInput { EnemyId = enemy.Id } });
}
}
}
}
```
## Query 的执行机制

View File

@ -185,11 +185,11 @@ public class GameArchitecture : Architecture
```csharp
// 在 Controller 中
public partial class GameController : Node, IController
public class GameController : IController
{
public IArchitecture GetArchitecture() => GameArchitecture.Interface;
public override void _Ready()
public void Start()
{
// 获取 System
var combatSystem = this.GetSystem<CombatSystem>();
@ -223,6 +223,61 @@ public class AISystem : AbstractSystem
## 常见使用模式
### 异步 System
System 支持异步初始化,通过实现 `IAsyncInitializable` 接口可以在初始化时执行异步操作。
```csharp
// 异步系统示例
public class DataLoadSystem : AbstractSystem, IAsyncInitializable
{
private GameData _gameData;
protected override void OnInit()
{
// 同步初始化逻辑
this.RegisterEvent<GameStartedEvent>(OnGameStarted);
}
public async Task InitializeAsync()
{
// 异步加载游戏数据
var storage = this.GetUtility<IStorageUtility>();
_gameData = await storage.LoadGameDataAsync();
// 数据加载完成后发送事件
this.SendEvent(new GameDataLoadedEvent { Data = _gameData });
}
private void OnGameStarted(GameStartedEvent e)
{
// 使用已加载的数据
Console.WriteLine($"Game data loaded: {_gameData.Version}");
}
protected override void OnDestroy()
{
// 清理资源
_gameData = null;
}
}
// 在架构中使用异步 System
public class GameArchitecture : Architecture
{
protected override void Init()
{
RegisterModel(new PlayerModel());
RegisterSystem(new DataLoadSystem());
RegisterSystem(new CombatSystem());
}
}
// 异步初始化架构
var architecture = new GameArchitecture();
await architecture.InitializeAsync();
```
### 1. 事件驱动的 System
```

107
docs/zh-CN/faq.md Normal file
View File

@ -0,0 +1,107 @@
# 常见问题FAQ
## 安装与配置
### Q: 如何安装 GFramework
A: 使用 NuGet 包管理器:
```bash
dotnet add package GeWuYou.GFramework.Core
```
详见 [安装配置](./getting-started/installation.md)。
### Q: 支持哪些 .NET 版本?
A: 支持 .NET 6.0 及更高版本(包括 .NET 7.0、8.0、9.0、10.0)。
### Q: 可以在 Unity 中使用吗?
A: Core 模块可以在 Unity 中使用。Godot 集成模块仅支持 Godot。
## 架构设计
### Q: 什么时候应该使用 Command
A: 当需要封装用户操作、支持撤销/重做或记录操作历史时。
### Q: 什么时候应该使用 Query
A: 当需要查询数据、检查条件或明确只读意图时。
### Q: 什么时候应该使用 Event
A: 当需要通知其他组件、实现松耦合通信或支持多个监听者时。
### Q: Model 中可以包含业务逻辑吗?
A: 不建议。Model 应该只存储数据。业务逻辑应该在 System 中实现。
## 性能优化
### Q: 频繁调用 GetModel 会有性能问题吗?
A: 不会,但建议缓存引用以提高效率。
### Q: 事件系统的性能如何?
A: 事件系统使用类型安全的泛型,性能优异。
### Q: BindableProperty 有性能开销吗?
A: 开销极小。仅在值变化时触发回调。
## 内存管理
### Q: 如何避免内存泄漏?
A: 使用 `UnRegisterList` 统一管理注销。
### Q: 销毁 Architecture 时会自动清理吗?
A: 是的。调用 `architecture.Destroy()` 会自动销毁所有组件。
## Godot 集成
### Q: 如何在 Godot 中使用 GFramework
A: 安装 Godot 集成包:
```bash
dotnet add package GeWuYou.GFramework.Godot
```
### Q: 支持哪个版本的 Godot
A: Godot 4.6 及更高版本。
## 测试
### Q: 如何测试使用 GFramework 的代码?
A: 通过依赖注入模拟架构进行单元测试。
## 最佳实践
### Q: 如何组织大型项目?
A: 按功能模块组织Models、Systems、Commands、Events 等)。
### Q: 如何处理异步操作?
A: 使用 async/await 结合事件系统。
### Q: 如何处理错误?
A: 使用事件传递错误信息。
## 许可证
### Q: GFramework 采用什么许可证?
A: Apache License 2.0。可用于商业项目。
---
**没有找到答案?** 在 [GitHub](https://github.com/GeWuYou/GFramework) 提交 Issue。

View File

@ -0,0 +1,306 @@
# 故障排除与调试
本指南帮助你诊断和解决 GFramework 使用中的常见问题。
## 常见错误
### 1. 组件未注册错误
**错误信息**`KeyNotFoundException: 未找到类型为 'XXX' 的组件`
**原因**:尝试获取未注册的组件。
**解决方案**
```csharp
// ❌ 错误:未注册 PlayerModel
var arch = new GameArchitecture();
arch.Initialize();
var model = arch.GetModel<PlayerModel>(); // 抛出异常
// ✅ 正确:先注册再获取
public class GameArchitecture : Architecture
{
protected override void Init()
{
RegisterModel(new PlayerModel()); // 注册模型
}
}
```
### 2. 事件监听器未触发
**问题**:注册了事件监听器但没有被调用。
**原因**
- 事件类型不匹配
- 监听器在事件发送前注销
- 事件发送时使用了错误的类型
**解决方案**
```csharp
// ❌ 错误:事件类型不匹配
this.RegisterEvent<PlayerDiedEvent>(OnPlayerDied);
this.SendEvent(new PlayerAttackedEvent()); // 不会触发
// ✅ 正确:事件类型匹配
this.RegisterEvent<PlayerAttackedEvent>(OnPlayerAttacked);
this.SendEvent(new PlayerAttackedEvent()); // 正确触发
```
### 3. 内存泄漏
**问题**:应用内存持续增长。
**原因**
- 未注销事件监听器
- 未注销属性监听器
- 未销毁 Architecture
**解决方案**
```csharp
// ✅ 正确:使用 UnRegisterList 管理注销
private IUnRegisterList _unregisterList = new UnRegisterList();
public void Initialize()
{
this.RegisterEvent<Event1>(OnEvent1)
.AddToUnregisterList(_unregisterList);
model.Property.Register(OnPropertyChanged)
.AddToUnregisterList(_unregisterList);
}
public void Cleanup()
{
_unregisterList.UnRegisterAll();
}
// ✅ 销毁架构
architecture.Destroy();
```
### 4. 循环依赖
**问题**:两个系统相互依赖导致死循环。
**原因**:系统间直接调用而不是通过事件通信。
**解决方案**
```csharp
// ❌ 错误:直接调用导致循环依赖
public class SystemA : AbstractSystem
{
private void OnEvent(EventA e)
{
var systemB = this.GetSystem<SystemB>();
systemB.DoSomething(); // 可能导致循环
}
}
// ✅ 正确:使用事件解耦
public class SystemA : AbstractSystem
{
private void OnEvent(EventA e)
{
this.SendEvent(new EventB()); // 发送事件
}
}
public class SystemB : AbstractSystem
{
protected override void OnInit()
{
this.RegisterEvent<EventB>(OnEventB);
}
}
```
## 调试技巧
### 1. 启用日志
```csharp
// 创建自定义日志系统
public class DebugLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine($"[GFramework] {message}");
}
}
// 在架构中注册
public class GameArchitecture : Architecture
{
protected override void Init()
{
RegisterUtility(new DebugLogger());
}
}
```
### 2. 追踪事件流
```csharp
// 创建事件追踪系统
public class EventTracer : AbstractSystem
{
protected override void OnInit()
{
// 监听所有事件(需要手动注册)
this.RegisterEvent<PlayerDiedEvent>(e =>
Console.WriteLine("Event: PlayerDiedEvent"));
this.RegisterEvent<PlayerAttackedEvent>(e =>
Console.WriteLine("Event: PlayerAttackedEvent"));
}
}
```
### 3. 检查组件状态
```csharp
// 创建调试工具
public class ArchitectureDebugger
{
public static void PrintArchitectureState(IArchitecture arch)
{
Console.WriteLine("=== Architecture State ===");
// 打印已注册的模型
Console.WriteLine("Models:");
// 需要通过反射或其他方式访问
// 打印已注册的系统
Console.WriteLine("Systems:");
// 需要通过反射或其他方式访问
}
}
```
### 4. 单元测试调试
```csharp
[Test]
public void DebugPlayerDamage()
{
var arch = new TestArchitecture();
arch.Initialize();
var player = arch.GetModel<PlayerModel>();
// 打印初始状态
Console.WriteLine($"Initial Health: {player.Health.Value}");
// 发送伤害事件
arch.SendEvent(new DamageEvent { Amount = 10 });
// 打印最终状态
Console.WriteLine($"Final Health: {player.Health.Value}");
// 验证
Assert.AreEqual(90, player.Health.Value);
}
```
## 性能问题
### 1. 事件处理缓慢
**问题**:事件处理耗时过长。
**诊断**
```csharp
// 测量事件处理时间
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
arch.SendEvent(new HeavyEvent());
stopwatch.Stop();
Console.WriteLine($"Event processing time: {stopwatch.ElapsedMilliseconds}ms");
```
**优化**
```csharp
// ❌ 低效:在事件处理中进行复杂计算
private void OnEvent(HeavyEvent e)
{
for (int i = 0; i < 1000000; i++)
{
// 复杂计算
}
}
// ✅ 高效:异步处理
private async void OnEvent(HeavyEvent e)
{
await Task.Run(() =>
{
for (int i = 0; i < 1000000; i++)
{
// 复杂计算
}
});
}
```
### 2. 频繁的 GetModel 调用
**问题**:每帧都调用 GetModel 导致性能下降。
**优化**
```csharp
// ❌ 低效
public void Update()
{
var model = _architecture.GetModel<PlayerModel>(); // 每帧调用
model.Health.Value -= 1;
}
// ✅ 高效
private PlayerModel _playerModel;
public void Initialize()
{
_playerModel = _architecture.GetModel<PlayerModel>(); // 只调用一次
}
public void Update()
{
_playerModel.Health.Value -= 1;
}
```
## 常见问题排查清单
- [ ] 所有组件都已注册?
- [ ] 事件类型是否匹配?
- [ ] 是否正确注销了监听器?
- [ ] Architecture 是否已初始化?
- [ ] 是否有循环依赖?
- [ ] 内存使用是否持续增长?
- [ ] 事件处理是否过于复杂?
- [ ] 是否缓存了频繁访问的组件?
## 获取帮助
如果问题仍未解决:
1. 查看 [常见问题](../faq.md)
2. 查看 [API 参考](../api-reference/index.md)
3. 在 [GitHub Issues](https://github.com/GeWuYou/GFramework/issues) 提交问题
4. 查看 [教程](../tutorials/index.md) 中的示例代码
---
**提示**:在提交 Issue 时,请提供:
- 错误信息和堆栈跟踪
- 最小化的复现代码
- 你的环境信息(.NET 版本、IDE 等)