From 1b9e81bbdb6022514b4b50e0254bc9f671f71f31 Mon Sep 17 00:00:00 2001
From: GeWuYou <95328647+GeWuYou@users.noreply.github.com>
Date: Sun, 8 Mar 2026 11:03:02 +0800
Subject: [PATCH] =?UTF-8?q?refactor(docs):=20=E5=B0=86=E6=8E=A7=E5=88=B6?=
=?UTF-8?q?=E5=99=A8=E5=AE=9E=E7=8E=B0=E8=BD=AC=E6=8D=A2=E4=B8=BA=E4=B8=8A?=
=?UTF-8?q?=E4=B8=8B=E6=96=87=E6=84=9F=E7=9F=A5=E6=A8=A1=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 将 IController 实现改为使用 [ContextAware] 特性和 partial 类
- 移除手动实现的 GetArchitecture 方法
- 将架构交互方法从 this 调用改为 Context 调用
- 添加必要的 using 语句以支持新的架构访问方式
- 更新所有涉及模型、系统、工具和事件的架构访问代码
- 统一架构访问模式以提高代码一致性和可维护性
---
.../controller/IController.cs | 46 +-
.../best-practices/architecture-patterns.md | 6886 ++++++++---------
docs/zh-CN/best-practices/index.md | 974 +--
docs/zh-CN/best-practices/performance.md | 2723 +++----
docs/zh-CN/core/architecture.md | 1212 +--
docs/zh-CN/core/command.md | 896 +--
docs/zh-CN/core/configuration.md | 1877 ++---
docs/zh-CN/core/ecs.md | 9 +-
docs/zh-CN/core/events.md | 1194 +--
docs/zh-CN/core/pause.md | 1847 ++---
docs/zh-CN/core/property.md | 861 ++-
docs/zh-CN/core/query.md | 12 +-
docs/zh-CN/core/state-machine.md | 1158 +--
docs/zh-CN/core/system.md | 1322 ++--
docs/zh-CN/game/data.md | 1186 +--
docs/zh-CN/game/scene.md | 1310 ++--
docs/zh-CN/game/serialization.md | 1513 ++--
docs/zh-CN/game/ui.md | 1005 +--
docs/zh-CN/getting-started/quick-start.md | 643 +-
docs/zh-CN/godot/architecture.md | 1208 +--
.../context-aware-generator.md | 780 +-
docs/zh-CN/source-generators/index.md | 1785 ++---
.../source-generators/logging-generator.md | 678 +-
.../zh-CN/tutorials/godot-complete-project.md | 1624 ++--
docs/zh-CN/tutorials/pause-system.md | 2268 +++---
.../zh-CN/tutorials/state-machine-tutorial.md | 1492 ++--
26 files changed, 18344 insertions(+), 18165 deletions(-)
diff --git a/GFramework.Core.Abstractions/controller/IController.cs b/GFramework.Core.Abstractions/controller/IController.cs
index 9372fd7..050f474 100644
--- a/GFramework.Core.Abstractions/controller/IController.cs
+++ b/GFramework.Core.Abstractions/controller/IController.cs
@@ -1,10 +1,38 @@
-namespace GFramework.Core.Abstractions.controller;
-
-///
-/// 控制器接口,定义了控制器的基本契约和行为规范
-///
-///
-/// 该接口为框架中的控制器组件提供统一的抽象定义,
-/// 用于实现控制器的标准功能和生命周期管理
-///
+namespace GFramework.Core.Abstractions.controller;
+
+///
+/// 控制器标记接口,用于标识控制器组件
+///
+///
+///
+/// IController 是一个标记接口(Marker Interface),不包含任何方法或属性。
+/// 它的作用是标识一个类是控制器,用于协调 Model、System 和 UI 之间的交互。
+///
+///
+/// 架构访问:控制器通常需要访问架构上下文。使用 [ContextAware] 特性
+/// 自动生成上下文访问能力:
+///
+///
+/// using GFramework.SourceGenerators.Abstractions.rule;
+///
+/// [ContextAware]
+/// public partial class PlayerController : IController
+/// {
+/// public void Initialize()
+/// {
+/// // Context 属性由 [ContextAware] 自动生成
+/// var playerModel = Context.GetModel<PlayerModel>();
+/// var gameSystem = Context.GetSystem<GameSystem>();
+/// }
+/// }
+///
+///
+/// 注意:
+///
+///
+/// - 必须添加 partial 关键字
+/// - [ContextAware] 特性会自动实现 IContextAware 接口
+/// - Context 属性提供架构上下文访问
+///
+///
public interface IController;
\ No newline at end of file
diff --git a/docs/zh-CN/best-practices/architecture-patterns.md b/docs/zh-CN/best-practices/architecture-patterns.md
index 7067b15..316a65e 100644
--- a/docs/zh-CN/best-practices/architecture-patterns.md
+++ b/docs/zh-CN/best-practices/architecture-patterns.md
@@ -1,3445 +1,3443 @@
-# 架构设计模式指南
-
-> 全面介绍 GFramework 中的架构设计模式,帮助你构建清晰、可维护、可扩展的游戏架构。
-
-## 📋 目录
-
-- [概述](#概述)
-- [MVC 模式](#mvc-模式)
-- [MVVM 模式](#mvvm-模式)
-- [命令模式](#命令模式)
-- [查询模式](#查询模式)
-- [事件驱动模式](#事件驱动模式)
-- [依赖注入模式](#依赖注入模式)
-- [服务定位器模式](#服务定位器模式)
-- [对象池模式](#对象池模式)
-- [状态模式](#状态模式)
-- [设计原则](#设计原则)
-- [架构分层](#架构分层)
-- [依赖管理](#依赖管理)
-- [事件系统设计](#事件系统设计)
-- [模块化架构](#模块化架构)
-- [错误处理策略](#错误处理策略)
-- [测试策略](#测试策略)
-- [重构指南](#重构指南)
-- [模式选择与组合](#模式选择与组合)
-- [常见问题](#常见问题)
-
-## 概述
-
-架构设计模式是经过验证的解决方案,用于解决软件开发中的常见问题。GFramework 内置了多种设计模式,帮助你构建高质量的游戏应用。
-
-### 为什么需要架构设计模式?
-
-1. **提高代码质量**:遵循最佳实践,减少 bug
-2. **增强可维护性**:清晰的结构,易于理解和修改
-3. **促进团队协作**:统一的代码风格和架构
-4. **提升可扩展性**:轻松添加新功能
-5. **简化测试**:解耦的组件更容易测试
-
-### GFramework 支持的核心模式
-
-| 模式 | 用途 | 核心组件 |
-|-----------|--------------|-------------------------|
-| **MVC** | 分离数据、视图和控制逻辑 | Model, Controller |
-| **MVVM** | 数据绑定和响应式 UI | Model, BindableProperty |
-| **命令模式** | 封装操作请求 | ICommand, CommandBus |
-| **查询模式** | 分离读操作 | IQuery, QueryBus |
-| **事件驱动** | 松耦合通信 | IEventBus, Event |
-| **依赖注入** | 控制反转 | IIocContainer |
-| **服务定位器** | 服务查找 | Architecture.GetSystem |
-| **对象池** | 对象复用 | IObjectPoolSystem |
-| **状态模式** | 状态管理 | IStateMachine |
-
-## MVC 模式
-
-### 概念
-
-MVC(Model-View-Controller)是一种将应用程序分为三个核心组件的架构模式:
-
-- **Model(模型)**:管理数据和业务逻辑
-- **View(视图)**:显示数据给用户
-- **Controller(控制器)**:处理用户输入,协调 Model 和 View
-
-### 在 GFramework 中的实现
-
-```csharp
-// Model - 数据层
-public class PlayerModel : AbstractModel
-{
- public BindableProperty<int> Health { get; } = new(100);
- public BindableProperty<int> Score { get; } = new(0);
- public BindableProperty<string> Name { get; } = new("Player");
-
- protected override void OnInit()
- {
- // 监听数据变化
- Health.Register(newHealth =>
- {
- if (newHealth <= 0)
- {
- this.SendEvent(new PlayerDiedEvent());
- }
- });
- }
-}
-
-// Controller - 控制层
-[ContextAware]
-public partial class PlayerController : Node, IController
-{
- private PlayerModel _playerModel;
-
- public override void _Ready()
- {
- _playerModel = Context.GetModel<PlayerModel>();
-
- // 监听数据变化,更新视图
- _playerModel.Health.Register(UpdateHealthUI);
- _playerModel.Score.Register(UpdateScoreUI);
- }
-
- // 处理用户输入
- public override void _Input(InputEvent @event)
- {
- if (@event is InputEventKey keyEvent && keyEvent.Pressed)
- {
- if (keyEvent.Keycode == Key.Space)
- {
- // 发送命令修改 Model
- Context.SendCommand(new AttackCommand());
- }
- }
- }
-
- // 更新视图
- private void UpdateHealthUI(int health)
- {
- var healthBar = GetNode<ProgressBar>("HealthBar");
- healthBar.Value = health;
- }
-
- private void UpdateScoreUI(int score)
- {
- var scoreLabel = GetNode<Label>("ScoreLabel");
- scoreLabel.Text = $"Score: {score}";
- }
-}
-
-// System - 业务逻辑层(可选)
-public class CombatSystem : AbstractSystem
-{
- protected override void OnInit()
- {
- this.RegisterEvent<AttackCommand>(OnAttack);
- }
-
- private void OnAttack(AttackCommand cmd)
- {
- var playerModel = this.GetModel<PlayerModel>();
- var enemyModel = this.GetModel<EnemyModel>();
-
- // 计算伤害
- int damage = CalculateDamage(playerModel, enemyModel);
- enemyModel.Health.Value -= damage;
-
- // 增加分数
- if (enemyModel.Health.Value <= 0)
- {
- playerModel.Score.Value += 100;
- }
- }
-
- private int CalculateDamage(PlayerModel player, EnemyModel enemy)
- {
- return 10; // 简化示例
- }
-}
-```
-
-### MVC 优势
-
-- ✅ **职责分离**:Model、View、Controller 各司其职
-- ✅ **易于测试**:可以独立测试每个组件
-- ✅ **可维护性高**:修改一个组件不影响其他组件
-- ✅ **支持多视图**:同一个 Model 可以有多个 View
-
-### 最佳实践
-
-1. **Model 只负责数据**:不包含 UI 逻辑
-2. **Controller 协调交互**:不直接操作 UI 细节
-3. **View 只负责显示**:不包含业务逻辑
-4. **使用事件通信**:Model 变化通过事件通知 Controller
-
-## MVVM 模式
-
-### 概念
-
-MVVM(Model-View-ViewModel)是 MVC 的变体,强调数据绑定和响应式编程:
-
-- **Model**:数据和业务逻辑
-- **View**:用户界面
-- **ViewModel**:View 的抽象,提供数据绑定
-
-### 在 GFramework 中的实现
-
-```csharp
-// Model - 数据层
-public class GameModel : AbstractModel
-{
- public BindableProperty<int> CurrentLevel { get; } = new(1);
- public BindableProperty<float> Progress { get; } = new(0f);
- public BindableProperty<bool> IsLoading { get; } = new(false);
-
- protected override void OnInit()
- {
- Progress.Register(progress =>
- {
- if (progress >= 1.0f)
- {
- this.SendEvent(new LevelCompletedEvent());
- }
- });
- }
-}
-
-// ViewModel - 视图模型(在 GFramework 中,Model 本身就是 ViewModel)
-public class PlayerViewModel : AbstractModel
-{
- private PlayerModel _playerModel;
-
- // 计算属性
- public BindableProperty<string> HealthText { get; } = new("");
- public BindableProperty<float> HealthPercentage { get; } = new(1.0f);
- public BindableProperty<bool> IsAlive { get; } = new(true);
-
- protected override void OnInit()
- {
- _playerModel = this.GetModel<PlayerModel>();
-
- // 绑定数据转换
- _playerModel.Health.Register(health =>
- {
- HealthText.Value = $"{health} / {_playerModel.MaxHealth.Value}";
- HealthPercentage.Value = (float)health / _playerModel.MaxHealth.Value;
- IsAlive.Value = health > 0;
- });
- }
-}
-
-// View - 视图层
-[ContextAware]
-public partial class PlayerView : Control, IController
-{
- private PlayerViewModel _viewModel;
- private Label _healthLabel;
- private ProgressBar _healthBar;
- private Panel _deathPanel;
-
- public override void _Ready()
- {
- _viewModel = Context.GetModel<PlayerViewModel>();
-
- _healthLabel = GetNode<Label>("HealthLabel");
- _healthBar = GetNode<ProgressBar>("HealthBar");
- _deathPanel = GetNode<Panel>("DeathPanel");
-
- // 数据绑定
- _viewModel.HealthText.Register(text => _healthLabel.Text = text);
- _viewModel.HealthPercentage.Register(pct => _healthBar.Value = pct * 100);
- _viewModel.IsAlive.Register(alive => _deathPanel.Visible = !alive);
- }
-}
-```
-
-### MVVM 优势
-
-- ✅ **自动更新 UI**:数据变化自动反映到界面
-- ✅ **减少样板代码**:不需要手动更新 UI
-- ✅ **易于测试**:ViewModel 可以独立测试
-- ✅ **支持复杂 UI**:适合数据驱动的界面
-
-### 最佳实践
-
-1. **使用 BindableProperty**:实现响应式数据
-2. **ViewModel 不依赖 View**:保持单向依赖
-3. **计算属性放在 ViewModel**:如百分比、格式化文本
-4. **避免在 View 中写业务逻辑**:只负责数据绑定
-
-## 命令模式
-
-### 概念
-
-命令模式将请求封装为对象,从而支持参数化、队列化、日志记录和撤销操作。
-
-### 在 GFramework 中的实现
-
-```csharp
-// 定义命令输入
-public class BuyItemInput : ICommandInput
-{
- public string ItemId { get; set; }
- public int Quantity { get; set; }
-}
-
-// 实现命令
-public class BuyItemCommand : AbstractCommand<BuyItemInput>
-{
- protected override void OnExecute(BuyItemInput input)
- {
- var playerModel = this.GetModel<PlayerModel>();
- var inventoryModel = this.GetModel<InventoryModel>();
- var shopModel = this.GetModel<ShopModel>();
-
- // 获取物品信息
- var item = shopModel.GetItem(input.ItemId);
- var totalCost = item.Price * input.Quantity;
-
- // 检查金币
- if (playerModel.Gold.Value < totalCost)
- {
- this.SendEvent(new InsufficientGoldEvent());
- return;
- }
-
- // 扣除金币
- playerModel.Gold.Value -= totalCost;
-
- // 添加物品
- inventoryModel.AddItem(input.ItemId, input.Quantity);
-
- // 发送事件
- this.SendEvent(new ItemPurchasedEvent
- {
- ItemId = input.ItemId,
- Quantity = input.Quantity,
- Cost = totalCost
- });
- }
-}
-
-// 使用命令
-public class ShopController : IController
-{
- public IArchitecture GetArchitecture() => GameArchitecture.Interface;
-
- public void OnBuyButtonClicked(string itemId, int quantity)
- {
- // 创建并发送命令
- var input = new BuyItemInput
- {
- ItemId = itemId,
- Quantity = quantity
- };
-
- this.SendCommand(new BuyItemCommand { Input = input });
- }
-}
-```
-
-### 支持撤销的命令
-
-```csharp
-public interface IUndoableCommand : ICommand
-{
- void Undo();
-}
-
-public class MoveCommand : AbstractCommand, IUndoableCommand
-{
- private Vector2 _previousPosition;
- private Vector2 _newPosition;
-
- public MoveCommand(Vector2 newPosition)
- {
- _newPosition = newPosition;
- }
-
- protected override void OnExecute()
- {
- var playerModel = this.GetModel<PlayerModel>();
- _previousPosition = playerModel.Position.Value;
- playerModel.Position.Value = _newPosition;
- }
-
- public void Undo()
- {
- var playerModel = this.GetModel<PlayerModel>();
- playerModel.Position.Value = _previousPosition;
- }
-}
-
-// 命令历史管理器
-public class CommandHistory
-{
- private readonly Stack<IUndoableCommand> _history = new();
-
- public void Execute(IUndoableCommand command)
- {
- command.Execute();
- _history.Push(command);
- }
-
- public void Undo()
- {
- if (_history.Count > 0)
- {
- var command = _history.Pop();
- command.Undo();
- }
- }
-}
-```
-
-### 命令模式优势
-
-- ✅ **解耦发送者和接收者**:调用者不需要知道实现细节
-- ✅ **支持撤销/重做**:保存命令历史
-- ✅ **支持队列和日志**:可以记录所有操作
-- ✅ **易于扩展**:添加新命令不影响现有代码
-
-### 最佳实践
-
-1. **命令保持原子性**:一个命令完成一个完整操作
-2. **使用输入对象传参**:避免构造函数参数过多
-3. **命令无状态**:执行完即可丢弃
-4. **发送事件通知结果**:而不是返回值
-
-## 查询模式
-
-### 概念
-
-查询模式(CQRS 的一部分)将读操作与写操作分离,查询只读取数据,不修改状态。
-
-### 在 GFramework 中的实现
-
-```csharp
-// 定义查询输入
-public class GetPlayerStatsInput : IQueryInput
-{
- public string PlayerId { get; set; }
-}
-
-// 定义查询结果
-public class PlayerStats
-{
- public int Level { get; set; }
- public int Health { get; set; }
- public int MaxHealth { get; set; }
- public int Attack { get; set; }
- public int Defense { get; set; }
- public int TotalPower { get; set; }
-}
-
-// 实现查询
-public class GetPlayerStatsQuery : AbstractQuery<GetPlayerStatsInput, PlayerStats>
-{
- protected override PlayerStats OnDo(GetPlayerStatsInput input)
- {
- var playerModel = this.GetModel<PlayerModel>();
- var equipmentModel = this.GetModel<EquipmentModel>();
-
- // 计算总战力
- int basePower = playerModel.Level.Value * 10;
- int equipmentPower = equipmentModel.GetTotalPower();
-
- return new PlayerStats
- {
- Level = playerModel.Level.Value,
- Health = playerModel.Health.Value,
- MaxHealth = playerModel.MaxHealth.Value,
- Attack = playerModel.Attack.Value + equipmentModel.GetAttackBonus(),
- Defense = playerModel.Defense.Value + equipmentModel.GetDefenseBonus(),
- TotalPower = basePower + equipmentPower
- };
- }
-}
-
-// 使用查询
-public class CharacterPanelController : IController
-{
- public IArchitecture GetArchitecture() => GameArchitecture.Interface;
-
- public void ShowCharacterStats()
- {
- var input = new GetPlayerStatsInput { PlayerId = "player1" };
- var query = new GetPlayerStatsQuery { Input = input };
- var stats = this.SendQuery(query);
-
- // 显示统计信息
- DisplayStats(stats);
- }
-
- private void DisplayStats(PlayerStats stats)
- {
- Console.WriteLine($"Level: {stats.Level}");
- Console.WriteLine($"Health: {stats.Health}/{stats.MaxHealth}");
- Console.WriteLine($"Attack: {stats.Attack}");
- Console.WriteLine($"Defense: {stats.Defense}");
- Console.WriteLine($"Total Power: {stats.TotalPower}");
- }
-}
-```
-
-### 复杂查询示例
-
-```csharp
-// 查询背包中可装备的物品
-public class GetEquippableItemsQuery : AbstractQuery<EmptyQueryInput, List<Item>>
-{
- protected override List<Item> OnDo(EmptyQueryInput input)
- {
- var inventoryModel = this.GetModel<InventoryModel>();
- var playerModel = this.GetModel<PlayerModel>();
-
- return inventoryModel.GetAllItems()
- .Where(item => item.Type == ItemType.Equipment)
- .Where(item => item.RequiredLevel <= playerModel.Level.Value)
- .OrderByDescending(item => item.Power)
- .ToList();
- }
-}
-
-// 组合查询
-public class CanUseSkillQuery : AbstractQuery<CanUseSkillInput, bool>
-{
- protected override bool OnDo(CanUseSkillInput input)
- {
- var playerModel = this.GetModel<PlayerModel>();
-
- // 查询技能消耗
- var costQuery = new GetSkillCostQuery { Input = new GetSkillCostInput { SkillId = input.SkillId } };
- var cost = this.SendQuery(costQuery);
-
- // 查询冷却状态
- var cooldownQuery = new IsSkillOnCooldownQuery { Input = new IsSkillOnCooldownInput { SkillId = input.SkillId } };
- var onCooldown = this.SendQuery(cooldownQuery);
-
- // 综合判断
- return playerModel.Mana.Value >= cost.ManaCost
- && !onCooldown
- && playerModel.Health.Value > 0;
- }
-}
-```
-
-### 查询模式优势
-
-- ✅ **职责分离**:读写操作明确分离
-- ✅ **易于优化**:可以针对查询进行缓存优化
-- ✅ **提高可读性**:查询意图清晰
-- ✅ **支持复杂查询**:可以组合多个简单查询
-
-### 最佳实践
-
-1. **查询只读取,不修改**:保持查询的纯粹性
-2. **使用清晰的命名**:Get、Is、Can、Has 等前缀
-3. **避免过度查询**:频繁查询考虑使用 BindableProperty
-4. **合理使用缓存**:复杂计算结果可以缓存
-
-## 事件驱动模式
-
-### 概念
-
-事件驱动模式通过事件实现组件间的松耦合通信。发送者不需要知道接收者,接收者通过订阅事件来响应变化。
-
-### 在 GFramework 中的实现
-
-```csharp
-// 定义事件
-public struct PlayerDiedEvent
-{
- public Vector3 Position { get; set; }
- public string Cause { get; set; }
- public int FinalScore { get; set; }
-}
-
-public struct EnemyKilledEvent
-{
- public string EnemyId { get; set; }
- public int Reward { get; set; }
-}
-
-// Model 发送事件
-public class PlayerModel : AbstractModel
-{
- public BindableProperty<int> Health { get; } = new(100);
- public BindableProperty<Vector3> Position { get; } = new(Vector3.Zero);
-
- protected override void OnInit()
- {
- Health.Register(newHealth =>
- {
- if (newHealth <= 0)
- {
- // 发送玩家死亡事件
- this.SendEvent(new PlayerDiedEvent
- {
- Position = Position.Value,
- Cause = "Health depleted",
- FinalScore = this.GetModel<GameModel>().Score.Value
- });
- }
- });
- }
-}
-
-// System 监听和发送事件
-public class AchievementSystem : AbstractSystem
-{
- private int _enemyKillCount = 0;
-
- protected override void OnInit()
- {
- // 监听敌人被杀事件
- this.RegisterEvent<EnemyKilledEvent>(OnEnemyKilled);
-
- // 监听玩家死亡事件
- this.RegisterEvent<PlayerDiedEvent>(OnPlayerDied);
- }
-
- private void OnEnemyKilled(EnemyKilledEvent e)
- {
- _enemyKillCount++;
-
- // 检查成就条件
- if (_enemyKillCount == 10)
- {
- this.SendEvent(new AchievementUnlockedEvent
- {
- AchievementId = "first_blood_10",
- Title = "新手猎人",
- Description = "击败10个敌人"
- });
- }
- }
-
- private void OnPlayerDied(PlayerDiedEvent e)
- {
- // 记录统计数据
- var statsModel = this.GetModel<StatisticsModel>();
- statsModel.RecordDeath(e.Position, e.Cause);
- }
-}
-
-// Controller 监听事件
-public class UIController : IController
-{
- private IUnRegisterList _unregisterList = new UnRegisterList();
-
- public IArchitecture GetArchitecture() => GameArchitecture.Interface;
-
- public void Initialize()
- {
- // 监听成就解锁事件
- this.RegisterEvent<AchievementUnlockedEvent>(OnAchievementUnlocked)
- .AddToUnregisterList(_unregisterList);
-
- // 监听玩家死亡事件
- this.RegisterEvent<PlayerDiedEvent>(OnPlayerDied)
- .AddToUnregisterList(_unregisterList);
- }
-
- private void OnAchievementUnlocked(AchievementUnlockedEvent e)
- {
- ShowAchievementNotification(e.Title, e.Description);
- }
-
- private void OnPlayerDied(PlayerDiedEvent e)
- {
- ShowGameOverScreen(e.FinalScore);
- }
-
- public void Cleanup()
- {
- _unregisterList.UnRegisterAll();
- }
-}
-```
-
-### 事件组合
-
-```csharp
-// 使用 OrEvent 组合多个事件
-public class InputController : IController
-{
- public void Initialize()
- {
- var onAnyInput = new OrEvent()
- .Or(keyboardEvent)
- .Or(mouseEvent)
- .Or(gamepadEvent);
-
- onAnyInput.Register(() =>
- {
- ResetIdleTimer();
- });
- }
-}
-```
-
-### 事件驱动模式优势
-
-- ✅ **松耦合**:发送者和接收者互不依赖
-- ✅ **一对多通信**:一个事件可以有多个监听者
-- ✅ **易于扩展**:添加新监听者不影响现有代码
-- ✅ **支持异步**:事件可以异步处理
-
-### 最佳实践
-
-1. **事件命名使用过去式**:PlayerDiedEvent、LevelCompletedEvent
-2. **事件使用结构体**:减少内存分配
-3. **及时注销事件**:使用 IUnRegisterList 管理
-4. **避免事件循环**:事件处理器中谨慎发送新事件
-
-## 依赖注入模式
-
-### 概念
-
-依赖注入(DI)是一种实现控制反转(IoC)的技术,通过外部注入依赖而不是在类内部创建。
-
-### 在 GFramework 中的实现
-
-```csharp
-// 定义接口
-public interface IStorageService
-{
- Task SaveAsync<T>(string key, T data);
- Task<T> LoadAsync<T>(string key);
-}
-
-public interface IAudioService
-{
- void PlaySound(string soundId);
- void PlayMusic(string musicId);
-}
-
-// 实现服务
-public class LocalStorageService : IStorageService
-{
- public async Task SaveAsync<T>(string key, T data)
- {
- var json = JsonSerializer.Serialize(data);
- await File.WriteAllTextAsync($"saves/{key}.json", json);
- }
-
- public async Task<T> LoadAsync<T>(string key)
- {
- var json = await File.ReadAllTextAsync($"saves/{key}.json");
- return JsonSerializer.Deserialize<T>(json);
- }
-}
-
-public class GodotAudioService : IAudioService
-{
- private AudioStreamPlayer _soundPlayer;
- private AudioStreamPlayer _musicPlayer;
-
- public void PlaySound(string soundId)
- {
- var sound = GD.Load<AudioStream>($"res://sounds/{soundId}.ogg");
- _soundPlayer.Stream = sound;
- _soundPlayer.Play();
- }
-
- public void PlayMusic(string musicId)
- {
- var music = GD.Load<AudioStream>($"res://music/{musicId}.ogg");
- _musicPlayer.Stream = music;
- _musicPlayer.Play();
- }
-}
-
-// 在架构中注册服务
-public class GameArchitecture : Architecture
-{
- protected override void Init()
- {
- // 注册服务实现
- RegisterUtility<IStorageService>(new LocalStorageService());
- RegisterUtility<IAudioService>(new GodotAudioService());
-
- // 注册 System(System 会自动获取依赖)
- RegisterSystem(new SaveSystem());
- RegisterSystem(new AudioSystem());
- }
-}
-
-// System 使用依赖注入
-public class SaveSystem : AbstractSystem
-{
- private IStorageService _storageService;
-
- protected override void OnInit()
- {
- // 从容器获取依赖
- _storageService = this.GetUtility<IStorageService>();
-
- this.RegisterEvent<SaveGameEvent>(OnSaveGame);
- }
-
- private async void OnSaveGame(SaveGameEvent e)
- {
- var playerModel = this.GetModel<PlayerModel>();
- var saveData = new SaveData
- {
- PlayerName = playerModel.Name.Value,
- Level = playerModel.Level.Value,
- Health = playerModel.Health.Value
- };
-
- await _storageService.SaveAsync("current_save", saveData);
- }
-}
-```
-
-### 构造函数注入(推荐)
-
-```csharp
-public class SaveSystem : AbstractSystem
-{
- private readonly IStorageService _storageService;
- private readonly IAudioService _audioService;
-
- // 通过构造函数注入依赖
- public SaveSystem(IStorageService storageService, IAudioService audioService)
- {
- _storageService = storageService;
- _audioService = audioService;
- }
-
- protected override void OnInit()
- {
- this.RegisterEvent<SaveGameEvent>(OnSaveGame);
- }
-
- private async void OnSaveGame(SaveGameEvent e)
- {
- await _storageService.SaveAsync("save", e.Data);
- _audioService.PlaySound("save_success");
- }
-}
-
-// 注册时传入依赖
-public class GameArchitecture : Architecture
-{
- protected override void Init()
- {
- var storageService = new LocalStorageService();
- var audioService = new GodotAudioService();
-
- RegisterUtility<IStorageService>(storageService);
- RegisterUtility<IAudioService>(audioService);
-
- // 构造函数注入
- RegisterSystem(new SaveSystem(storageService, audioService));
- }
-}
-```
-
-### 依赖注入优势
-
-- ✅ **易于测试**:可以注入模拟对象
-- ✅ **松耦合**:依赖接口而非实现
-- ✅ **灵活配置**:运行时选择实现
-- ✅ **提高可维护性**:依赖关系清晰
-
-### 最佳实践
-
-1. **依赖接口而非实现**:使用 IStorageService 而非 LocalStorageService
-2. **优先使用构造函数注入**:依赖关系更明确
-3. **避免循环依赖**:System 不应相互依赖
-4. **使用 IoC 容器管理生命周期**:让框架管理对象创建
-
-## 服务定位器模式
-
-### 概念
-
-服务定位器模式提供一个全局访问点来获取服务,是依赖注入的替代方案。
-
-### 在 GFramework 中的实现
-
-```csharp
-// GFramework 的 Architecture 本身就是服务定位器
-public class GameplaySystem : AbstractSystem
-{
- protected override void OnInit()
- {
- // 通过服务定位器获取服务
- var playerModel = this.GetModel<PlayerModel>();
- var audioSystem = this.GetSystem<AudioSystem>();
- var storageUtility = this.GetUtility<IStorageUtility>();
-
- // 使用服务
- playerModel.Health.Value = 100;
- audioSystem.PlayBGM("gameplay");
- }
-}
-
-// 在 Controller 中使用
-public class MenuController : IController
-{
- public IArchitecture GetArchitecture() => GameArchitecture.Interface;
-
- public void OnStartButtonClicked()
- {
- // 通过架构获取服务
- var gameModel = this.GetModel<GameModel>();
- gameModel.GameState.Value = GameState.Playing;
-
- // 发送命令
- this.SendCommand(new StartGameCommand());
- }
-}
-```
-
-### 自定义服务定位器
-
-```csharp
-// 创建专门的服务定位器
-public static class ServiceLocator
-{
- private static readonly Dictionary<Type, object> _services = new();
-
- public static void Register<T>(T service)
- {
- _services[typeof(T)] = service;
- }
-
- public static T Get<T>()
- {
- if (_services.TryGetValue(typeof(T), out var service))
- {
- return (T)service;
- }
- throw new InvalidOperationException($"Service {typeof(T)} not registered");
- }
-
- public static void Clear()
- {
- _services.Clear();
- }
-}
-
-// 使用自定义服务定位器
-public class GameInitializer
-{
- public void Initialize()
- {
- // 注册服务
- ServiceLocator.Register<IAnalyticsService>(new AnalyticsService());
- ServiceLocator.Register<ILeaderboardService>(new LeaderboardService());
- }
-}
-
-public class GameOverScreen
-{
- public void SubmitScore(int score)
- {
- // 获取服务
- var leaderboard = ServiceLocator.Get<ILeaderboardService>();
- leaderboard.SubmitScore(score);
-
- var analytics = ServiceLocator.Get<IAnalyticsService>();
- analytics.TrackEvent("game_over", new { score });
- }
-}
-```
-
-### 服务定位器 vs 依赖注入
-
-| 特性 | 服务定位器 | 依赖注入 |
-|-----------|--------------|------------|
-| **依赖可见性** | 隐式(运行时获取) | 显式(构造函数参数) |
-| **易用性** | 简单直接 | 需要配置 |
-| **测试性** | 较难(需要模拟全局状态) | 容易(注入模拟对象) |
-| **编译时检查** | 无 | 有 |
-| **适用场景** | 快速原型、小项目 | 大型项目、团队协作 |
-
-### 最佳实践
-
-1. **小项目使用服务定位器**:简单直接
-2. **大项目使用依赖注入**:更易维护
-3. **避免过度使用**:不要把所有东西都放入定位器
-4. **提供清晰的 API**:GetModel、GetSystem、GetUtility
-
-## 对象池模式
-
-### 概念
-
-对象池模式通过复用对象来减少内存分配和垃圾回收,提高性能。
-
-### 在 GFramework 中的实现
-
-```csharp
-// 定义可池化对象
-public class Bullet : Node2D, IPoolableNode
-{
- public bool IsInPool { get; set; }
-
- public void OnSpawn()
- {
- // 从池中取出时调用
- Visible = true;
- IsInPool = false;
- }
-
- public void OnRecycle()
- {
- // 回收到池中时调用
- Visible = false;
- IsInPool = true;
- Position = Vector2.Zero;
- Rotation = 0;
- }
-}
-
-// 创建对象池系统
-public class BulletPoolSystem : AbstractNodePoolSystem<Bullet>
-{
- protected override Bullet CreateInstance()
- {
- var bullet = new Bullet();
- // 初始化子弹
- return bullet;
- }
-
- protected override void OnInit()
- {
- // 预创建对象
- PrewarmPool(50);
- }
-}
-
-// 使用对象池
-public class WeaponSystem : AbstractSystem
-{
- private BulletPoolSystem _bulletPool;
-
- protected override void OnInit()
- {
- _bulletPool = this.GetSystem<BulletPoolSystem>();
- this.RegisterEvent<FireWeaponEvent>(OnFireWeapon);
- }
-
- private void OnFireWeapon(FireWeaponEvent e)
- {
- // 从池中获取子弹
- var bullet = _bulletPool.Spawn();
- bullet.Position = e.Position;
- bullet.Rotation = e.Direction;
-
- // 3秒后回收
- ScheduleRecycle(bullet, 3.0f);
- }
-
- private async void ScheduleRecycle(Bullet bullet, float delay)
- {
- await Task.Delay((int)(delay * 1000));
- _bulletPool.Recycle(bullet);
- }
-}
-```
-
-### 通用对象池
-
-```csharp
-// 通用对象池实现
-public class ObjectPool<T> where T : class, new()
-{
- private readonly Stack<T> _pool = new();
- private readonly Action<T> _onSpawn;
- private readonly Action<T> _onRecycle;
- private readonly int _maxSize;
-
- public ObjectPool(int initialSize = 10, int maxSize = 100,
- Action<T> onSpawn = null, Action<T> onRecycle = null)
- {
- _maxSize = maxSize;
- _onSpawn = onSpawn;
- _onRecycle = onRecycle;
-
- // 预创建对象
- for (int i = 0; i < initialSize; i++)
- {
- _pool.Push(new T());
- }
- }
-
- public T Spawn()
- {
- T obj = _pool.Count > 0 ? _pool.Pop() : new T();
- _onSpawn?.Invoke(obj);
- return obj;
- }
-
- public void Recycle(T obj)
- {
- if (_pool.Count < _maxSize)
- {
- _onRecycle?.Invoke(obj);
- _pool.Push(obj);
- }
- }
-
- public void Clear()
- {
- _pool.Clear();
- }
-}
-
-// 使用通用对象池
-public class ParticleSystem : AbstractSystem
-{
- private ObjectPool<Particle> _particlePool;
-
- protected override void OnInit()
- {
- _particlePool = new ObjectPool<Particle>(
- initialSize: 100,
- maxSize: 500,
- onSpawn: p => p.Reset(),
- onRecycle: p => p.Clear()
- );
- }
-
- public void EmitParticles(Vector3 position, int count)
- {
- for (int i = 0; i < count; i++)
- {
- var particle = _particlePool.Spawn();
- particle.Position = position;
- particle.Velocity = GetRandomVelocity();
- }
- }
-}
-```
-
-### 对象池优势
-
-- ✅ **减少 GC 压力**:复用对象,减少内存分配
-- ✅ **提高性能**:避免频繁创建销毁对象
-- ✅ **稳定帧率**:减少 GC 导致的卡顿
-- ✅ **适合高频对象**:子弹、粒子、特效等
-
-### 最佳实践
-
-1. **预热池**:提前创建对象避免运行时分配
-2. **设置最大容量**:防止池无限增长
-3. **重置对象状态**:OnRecycle 中清理状态
-4. **监控池使用情况**:记录 Spawn/Recycle 次数
-
-## 状态模式
-
-### 概念
-
-状态模式允许对象在内部状态改变时改变其行为,将状态相关的行为封装到独立的状态类中。
-
-### 在 GFramework 中的实现
-
-```csharp
-// 定义游戏状态
-public class MenuState : ContextAwareStateBase
-{
- public override void OnEnter(IState from)
- {
- Console.WriteLine("进入菜单状态");
-
- // 显示菜单 UI
- var uiSystem = this.GetSystem<UISystem>();
- uiSystem.ShowMenu();
-
- // 播放菜单音乐
- var audioSystem = this.GetSystem<AudioSystem>();
- audioSystem.PlayBGM("menu_theme");
- }
-
- public override void OnExit(IState to)
- {
- Console.WriteLine("退出菜单状态");
-
- // 隐藏菜单 UI
- var uiSystem = this.GetSystem<UISystem>();
- uiSystem.HideMenu();
- }
-
- public override bool CanTransitionTo(IState target)
- {
- // 菜单可以转换到游戏或设置状态
- return target is GameplayState or SettingsState;
- }
-}
-
-public class GameplayState : ContextAwareStateBase
-{
- public override void OnEnter(IState from)
- {
- Console.WriteLine("进入游戏状态");
-
- // 初始化游戏
- var gameModel = this.GetModel<GameModel>();
- gameModel.Reset();
-
- // 加载关卡
- this.SendCommand(new LoadLevelCommand { LevelId = 1 });
-
- // 播放游戏音乐
- var audioSystem = this.GetSystem<AudioSystem>();
- audioSystem.PlayBGM("gameplay_theme");
- }
-
- public override void OnExit(IState to)
- {
- Console.WriteLine("退出游戏状态");
-
- // 保存游戏进度
- this.SendCommand(new SaveGameCommand());
- }
-
- public override bool CanTransitionTo(IState target)
- {
- // 游戏中可以暂停或结束
- return target is PauseState or GameOverState;
- }
-}
-
-public class PauseState : ContextAwareStateBase
-{
- public override void OnEnter(IState from)
- {
- Console.WriteLine("进入暂停状态");
-
- // 暂停游戏
- var timeSystem = this.GetSystem<TimeSystem>();
- timeSystem.Pause();
-
- // 显示暂停菜单
- var uiSystem = this.GetSystem<UISystem>();
- uiSystem.ShowPauseMenu();
- }
-
- public override void OnExit(IState to)
- {
- Console.WriteLine("退出暂停状态");
-
- // 恢复游戏
- var timeSystem = this.GetSystem<TimeSystem>();
- timeSystem.Resume();
-
- // 隐藏暂停菜单
- var uiSystem = this.GetSystem<UISystem>();
- uiSystem.HidePauseMenu();
- }
-
- public override bool CanTransitionTo(IState target)
- {
- // 暂停只能返回游戏或退出到菜单
- return target is GameplayState or MenuState;
- }
-}
-
-// 注册状态机
-public class GameArchitecture : Architecture
-{
- protected override void Init()
- {
- // 创建状态机系统
- var stateMachine = new StateMachineSystem();
-
- // 注册所有状态
- stateMachine
- .Register(new MenuState())
- .Register(new GameplayState())
- .Register(new PauseState())
- .Register(new GameOverState())
- .Register(new SettingsState());
-
- RegisterSystem<IStateMachineSystem>(stateMachine);
- }
-}
-
-// 使用状态机
-public class GameController : IController
-{
- public IArchitecture GetArchitecture() => GameArchitecture.Interface;
-
- public async Task StartGame()
- {
- var stateMachine = this.GetSystem<IStateMachineSystem>();
- await stateMachine.ChangeToAsync<GameplayState>();
- }
-
- public async Task PauseGame()
- {
- var stateMachine = this.GetSystem<IStateMachineSystem>();
- await stateMachine.ChangeToAsync<PauseState>();
- }
-
- public async Task ResumeGame()
- {
- var stateMachine = this.GetSystem<IStateMachineSystem>();
- await stateMachine.ChangeToAsync<GameplayState>();
- }
-}
-```
-
-### 异步状态
-
-```csharp
-public class LoadingState : AsyncContextAwareStateBase
-{
- public override async Task OnEnterAsync(IState from)
- {
- Console.WriteLine("开始加载...");
-
- // 显示加载界面
- var uiSystem = this.GetSystem<UISystem>();
- uiSystem.ShowLoadingScreen();
-
- // 异步加载资源
- await LoadResourcesAsync();
-
- Console.WriteLine("加载完成");
-
- // 自动切换到游戏状态
- var stateMachine = this.GetSystem<IStateMachineSystem>();
- await stateMachine.ChangeToAsync<GameplayState>();
- }
-
- private async Task LoadResourcesAsync()
- {
- // 模拟异步加载
- await Task.Delay(2000);
- }
-
- public override async Task OnExitAsync(IState to)
- {
- // 隐藏加载界面
- var uiSystem = this.GetSystem<UISystem>();
- uiSystem.HideLoadingScreen();
-
- await Task.CompletedTask;
- }
-}
-```
-
-### 状态模式优势
-
-- ✅ **清晰的状态管理**:每个状态独立封装
-- ✅ **易于扩展**:添加新状态不影响现有代码
-- ✅ **状态转换验证**:CanTransitionTo 控制合法转换
-- ✅ **支持异步操作**:异步状态处理加载等操作
-
-### 最佳实践
-
-1. **状态保持单一职责**:每个状态只负责一个场景
-2. **使用转换验证**:防止非法状态转换
-3. **在 OnEnter 初始化,OnExit 清理**:保持状态独立
-4. **异步操作使用异步状态**:避免阻塞主线程
-
-## 设计原则
-
-### 1. 单一职责原则 (SRP)
-
-确保每个类只负责一个功能领域:
-
-```csharp
-// ✅ 好的做法:职责单一
-public class PlayerMovementController : AbstractSystem
-{
- protected override void OnInit()
- {
- this.RegisterEvent(OnPlayerInput);
- }
-
- private void OnPlayerInput(PlayerInputEvent e)
- {
- // 只负责移动逻辑
- ProcessMovement(e.Direction);
- }
-
- private void ProcessMovement(Vector2 direction)
- {
- // 移动相关的业务逻辑
- }
-}
-
-public class PlayerCombatController : AbstractSystem
-{
- protected override void OnInit()
- {
- this.RegisterEvent(OnAttackInput);
- }
-
- private void OnAttackInput(AttackInputEvent e)
- {
- // 只负责战斗逻辑
- ProcessAttack(e.Target);
- }
-
- private void ProcessAttack(Entity target)
- {
- // 战斗相关的业务逻辑
- }
-}
-
-// ❌ 避免:职责混乱
-public class PlayerController : AbstractSystem
-{
- private void OnPlayerInput(PlayerInputEvent e)
- {
- // 移动逻辑
- ProcessMovement(e.Direction);
-
- // 战斗逻辑
- if (e.IsAttacking)
- {
- ProcessAttack(e.Target);
- }
-
- // UI逻辑
- UpdateHealthBar();
-
- // 音效逻辑
- PlaySoundEffect();
-
- // 存档逻辑
- SaveGame();
-
- // 职责太多,难以维护
- }
-}
-```
-
-### 2. 开闭原则 (OCP)
-
-设计应该对扩展开放,对修改封闭:
-
-```csharp
-// ✅ 好的做法:使用接口和策略模式
-public interface IWeaponStrategy
-{
- void Attack(Entity attacker, Entity target);
- int CalculateDamage(Entity attacker, Entity target);
-}
-
-public class SwordWeaponStrategy : IWeaponStrategy
-{
- public void Attack(Entity attacker, Entity target)
- {
- var damage = CalculateDamage(attacker, target);
- target.TakeDamage(damage);
- PlaySwingAnimation();
- }
-
- public int CalculateDamage(Entity attacker, Entity target)
- {
- return attacker.Strength + GetSwordBonus() - target.Armor;
- }
-}
-
-public class MagicWeaponStrategy : IWeaponStrategy
-{
- public void Attack(Entity attacker, Entity target)
- {
- var damage = CalculateDamage(attacker, target);
- target.TakeDamage(damage);
- CastMagicEffect();
- }
-
- public int CalculateDamage(Entity attacker, Entity target)
- {
- return attacker.Intelligence * 2 + GetMagicBonus() - target.MagicResistance;
- }
-}
-
-public class CombatSystem : AbstractSystem
-{
- private readonly Dictionary _weaponStrategies;
-
- public CombatSystem()
- {
- _weaponStrategies = new()
- {
- { WeaponType.Sword, new SwordWeaponStrategy() },
- { WeaponType.Magic, new MagicWeaponStrategy() }
- };
- }
-
- public void Attack(Entity attacker, Entity target)
- {
- var weaponType = attacker.EquippedWeapon.Type;
-
- if (_weaponStrategies.TryGetValue(weaponType, out var strategy))
- {
- strategy.Attack(attacker, target);
- }
- }
-
- // 添加新武器类型时,只需要添加新的策略,不需要修改现有代码
- public void RegisterWeaponStrategy(WeaponType type, IWeaponStrategy strategy)
- {
- _weaponStrategies[type] = strategy;
- }
-}
-
-// ❌ 避免:需要修改现有代码来扩展
-public class CombatSystem : AbstractSystem
-{
- public void Attack(Entity attacker, Entity target)
- {
- var weaponType = attacker.EquippedWeapon.Type;
-
- switch (weaponType)
- {
- case WeaponType.Sword:
- // 剑的攻击逻辑
- break;
- case WeaponType.Bow:
- // 弓的攻击逻辑
- break;
- default:
- throw new NotSupportedException($"Weapon type {weaponType} not supported");
- }
-
- // 添加新武器类型时需要修改这里的 switch 语句
- }
-}
-```
-
-### 3. 依赖倒置原则 (DIP)
-
-高层模块不应该依赖低层模块,两者都应该依赖抽象:
-
-```csharp
-// ✅ 好的做法:依赖抽象
-public interface IDataStorage
-{
- Task SaveAsync<T>(string key, T data);
- Task<T> LoadAsync<T>(string key, T defaultValue = default);
- Task ExistsAsync(string key);
-}
-
-public class FileStorage : IDataStorage
-{
- public async Task SaveAsync<T>(string key, T data)
- {
- var json = JsonConvert.SerializeObject(data);
- await File.WriteAllTextAsync(GetFilePath(key), json);
- }
-
- public async Task<T> LoadAsync<T>(string key, T defaultValue = default)
- {
- var filePath = GetFilePath(key);
- if (!File.Exists(filePath))
- return defaultValue;
-
- var json = await File.ReadAllTextAsync(filePath);
- return JsonConvert.DeserializeObject<T>(json);
- }
-
- public async Task ExistsAsync(string key)
- {
- return File.Exists(GetFilePath(key));
- }
-
- private string GetFilePath(string key)
- {
- return $"saves/{key}.json";
- }
-}
-
-public class CloudStorage : IDataStorage
-{
- public async Task SaveAsync<T>(string key, T data)
- {
- // 云存储实现
- await UploadToCloud(key, data);
- }
-
- public async Task<T> LoadAsync<T>(string key, T defaultValue = default)
- {
- // 云存储实现
- return await DownloadFromCloud<T>(key, defaultValue);
- }
-
- public async Task ExistsAsync(string key)
- {
- // 云存储实现
- return await CheckCloudExists(key);
- }
-}
-
-// 高层模块依赖抽象
-public class SaveSystem : AbstractSystem
-{
- private readonly IDataStorage _storage;
-
- public SaveSystem(IDataStorage storage)
- {
- _storage = storage;
- }
-
- public async Task SaveGameAsync(SaveData data)
- {
- await _storage.SaveAsync("current_save", data);
- }
-
- public async Task LoadGameAsync()
- {
- return await _storage.LoadAsync("current_save");
- }
-}
-
-// ❌ 避免:依赖具体实现
-public class SaveSystem : AbstractSystem
-{
- private readonly FileStorage _storage; // 直接依赖具体实现
-
- public SaveSystem()
- {
- _storage = new FileStorage(); // 硬编码依赖
- }
-
- // 无法轻松切换到其他存储方式
-}
-```
-
-## 架构分层
-
-### 1. 清晰的层次结构
-
-```csharp
-// ✅ 好的做法:清晰的分层架构
-namespace Game.Models
-{
- // 数据层:只负责存储状态
- public class PlayerModel : AbstractModel
- {
- public BindableProperty Health { get; } = new(100);
- public BindableProperty MaxHealth { get; } = new(100);
- public BindableProperty Position { get; } = new(Vector2.Zero);
- public BindableProperty State { get; } = new(PlayerState.Idle);
-
- protected override void OnInit()
- {
- // 只处理数据相关的逻辑
- Health.Register(OnHealthChanged);
- }
-
- private void OnHealthChanged(int newHealth)
- {
- if (newHealth <= 0)
- {
- State.Value = PlayerState.Dead;
- SendEvent(new PlayerDeathEvent());
- }
- }
- }
-
- public enum PlayerState
- {
- Idle,
- Moving,
- Attacking,
- Dead
- }
-}
-
-namespace Game.Systems
-{
- // 业务逻辑层:处理游戏逻辑
- public class PlayerMovementSystem : AbstractSystem
- {
- private PlayerModel _playerModel;
- private GameModel _gameModel;
-
- protected override void OnInit()
- {
- _playerModel = GetModel();
- _gameModel = GetModel();
-
- this.RegisterEvent(OnPlayerInput);
- }
-
- private void OnPlayerInput(PlayerInputEvent e)
- {
- if (_gameModel.State.Value != GameState.Playing)
- return;
-
- if (_playerModel.State.Value == PlayerState.Dead)
- return;
-
- // 处理移动逻辑
- ProcessMovement(e.Direction);
- }
-
- private void ProcessMovement(Vector2 direction)
- {
- if (direction != Vector2.Zero)
- {
- _playerModel.Position.Value += direction.Normalized() * GetMovementSpeed();
- _playerModel.State.Value = PlayerState.Moving;
-
- SendEvent(new PlayerMovedEvent {
- NewPosition = _playerModel.Position.Value,
- Direction = direction
- });
- }
- else
- {
- _playerModel.State.Value = PlayerState.Idle;
- }
- }
-
- private float GetMovementSpeed()
- {
- // 从玩家属性或其他地方获取速度
- return 5.0f;
- }
- }
-}
-
-namespace Game.Controllers
-{
- // 控制层:连接用户输入和业务逻辑
- [ContextAware]
- public partial class PlayerController : Node, IController
- {
- private PlayerModel _playerModel;
-
- public override void _Ready()
- {
- _playerModel = Context.GetModel();
-
- // 监听用户输入
- SetProcessInput(true);
-
- // 监听数据变化,更新UI
- _playerModel.Health.Register(UpdateHealthUI);
- _playerModel.Position.Register(UpdatePosition);
- }
-
- public override void _Input(InputEvent @event)
- {
- if (@event is InputEventKey keyEvent && keyEvent.Pressed)
- {
- var direction = GetInputDirection(keyEvent);
- Context.SendEvent(new PlayerInputEvent { Direction = direction });
- }
- }
-
- private void UpdateHealthUI(int health)
- {
- // 更新UI显示
- var healthBar = GetNode("UI/HealthBar");
- healthBar.Value = (float)health / _playerModel.MaxHealth.Value * 100;
- }
-
- private void UpdatePosition(Vector2 position)
- {
- // 更新玩家位置
- Position = position;
- }
-
- private Vector2 GetInputDirection(InputEventKey keyEvent)
- {
- return keyEvent.Keycode switch
- {
- Key.W => Vector2.Up,
- Key.S => Vector2.Down,
- Key.A => Vector2.Left,
- Key.D => Vector2.Right,
- _ => Vector2.Zero
- };
- }
- }
-}
-```
-
-### 2. 避免层次混乱
-
-```csharp
-// ❌ 避免:层次混乱
-public class PlayerController : Node, IController
-{
- // 混合了数据层、业务逻辑层和控制层的职责
- public BindableProperty Health { get; } = new(100); // 数据层职责
-
- public override void _Input(InputEvent @event) // 控制层职责
- {
- if (@event is InputEventKey keyEvent && keyEvent.Pressed)
- {
- if (keyEvent.Keycode == Key.W)
- {
- Position += Vector2.Up * MovementSpeed; // 业务逻辑层职责
- }
-
- if (keyEvent.Keycode == Key.Space)
- {
- Health -= 10; // 业务逻辑层职责
- PlaySoundEffect(); // 业务逻辑层职责
- }
- }
- }
-
- // 这样会导致代码难以测试和维护
-}
-```
-
-## 依赖管理
-
-### 1. 构造函数注入
-
-```csharp
-// ✅ 好的做法:构造函数注入
-public class PlayerCombatSystem : AbstractSystem
-{
- private readonly PlayerModel _playerModel;
- private readonly IWeaponService _weaponService;
- private readonly ISoundService _soundService;
- private readonly IEffectService _effectService;
-
- // 通过构造函数注入依赖
- public PlayerCombatSystem(
- PlayerModel playerModel,
- IWeaponService weaponService,
- ISoundService soundService,
- IEffectService effectService)
- {
- _playerModel = playerModel;
- _weaponService = weaponService;
- _soundService = soundService;
- _effectService = effectService;
- }
-
- protected override void OnInit()
- {
- this.RegisterEvent(OnAttack);
- }
-
- private void OnAttack(AttackEvent e)
- {
- var weapon = _weaponService.GetEquippedWeapon(_playerModel);
- var damage = _weaponService.CalculateDamage(weapon, e.Target);
-
- e.Target.TakeDamage(damage);
- _soundService.PlayAttackSound(weapon.Type);
- _effectService.PlayAttackEffect(_playerModel.Position, weapon.Type);
- }
-}
-
-// ❌ 避免:依赖注入容器
-public class PlayerCombatSystem : AbstractSystem
-{
- private PlayerModel _playerModel;
- private IWeaponService _weaponService;
- private ISoundService _soundService;
- private IEffectService _effectService;
-
- protected override void OnInit()
- {
- // 在运行时获取依赖,难以测试
- _playerModel = GetModel();
- _weaponService = GetService();
- _soundService = GetService();
- _effectService = GetService();
- }
-
- // 测试时难以模拟依赖
-}
-```
-
-### 2. 接口隔离
-
-```csharp
-// ✅ 好的做法:小而专注的接口
-public interface IMovementController
-{
- void Move(Vector2 direction);
- void Stop();
- bool CanMove();
-}
-
-public interface ICombatController
-{
- void Attack(Entity target);
- void Defend();
- bool CanAttack();
-}
-
-public interface IUIController
-{
- void ShowHealthBar();
- void HideHealthBar();
- void UpdateHealthDisplay(int currentHealth, int maxHealth);
-}
-
-public class PlayerController : Node, IMovementController, ICombatController, IUIController
-{
- // 实现各个接口,职责清晰
-}
-
-// ❌ 避免:大而全的接口
-public interface IPlayerController
-{
- void Move(Vector2 direction);
- void Stop();
- void Attack(Entity target);
- void Defend();
- void ShowHealthBar();
- void HideHealthBar();
- void UpdateHealthDisplay(int currentHealth, int maxHealth);
- void SaveGame();
- void LoadGame();
- void Respawn();
- void PlayAnimation(string animationName);
- void StopAnimation();
- // ... 更多方法,接口过于庞大
-}
-```
-
-## 事件系统设计
-
-### 1. 事件命名和结构
-
-```csharp
-// ✅ 好的做法:清晰的事件命名和结构
-public struct PlayerHealthChangedEvent
-{
- public int PreviousHealth { get; }
- public int NewHealth { get; }
- public int MaxHealth { get; }
- public Vector3 DamagePosition { get; }
- public DamageType DamageType { get; }
-}
-
-public struct PlayerDiedEvent
-{
- public Vector3 DeathPosition { get; }
- public string CauseOfDeath { get; }
- public TimeSpan SurvivalTime { get; }
-}
-
-public struct WeaponEquippedEvent
-{
- public string PlayerId { get; }
- public WeaponType WeaponType { get; }
- public string WeaponId { get; }
-}
-
-// ❌ 避免:模糊的事件命名和结构
-public struct PlayerEvent
-{
- public EventType Type { get; }
- public object Data { get; } // 类型不安全
- public Dictionary Properties { get; } // 难以理解
-}
-```
-
-### 2. 事件处理职责
-
-```csharp
-// ✅ 好的做法:单一职责的事件处理
-public class UIHealthBarController : AbstractSystem
-{
- protected override void OnInit()
- {
- this.RegisterEvent(OnPlayerHealthChanged);
- this.RegisterEvent(OnPlayerDied);
- }
-
- private void OnPlayerHealthChanged(PlayerHealthChangedEvent e)
- {
- UpdateHealthBar(e.NewHealth, e.MaxHealth);
-
- if (e.NewHealth < e.PreviousHealth)
- {
- ShowDamageEffect(e.DamagePosition, e.PreviousHealth - e.NewHealth);
- }
- }
-
- private void OnPlayerDied(PlayerDiedEvent e)
- {
- HideHealthBar();
- ShowDeathScreen(e.CauseOfDeath);
- }
-}
-
-public class AudioController : AbstractSystem
-{
- protected override void OnInit()
- {
- this.RegisterEvent(OnPlayerHealthChanged);
- this.RegisterEvent(OnPlayerDied);
- }
-
- private void OnPlayerHealthChanged(PlayerHealthChangedEvent e)
- {
- if (e.NewHealth < e.PreviousHealth)
- {
- PlayHurtSound(e.DamageType);
- }
- }
-
- private void OnPlayerDied(PlayerDiedEvent e)
- {
- PlayDeathSound();
- }
-}
-
-// ❌ 避免:一个处理器处理多种不相关的事件
-public class PlayerEventHandler : AbstractSystem
-{
- protected override void OnInit()
- {
- this.RegisterEvent(OnPlayerHealthChanged);
- this.RegisterEvent(OnPlayerDied);
- this.RegisterEvent(OnWeaponEquipped);
- this.RegisterEvent(OnLevelUp);
- // 注册太多事件,职责混乱
- }
-
- private void OnPlayerHealthChanged(PlayerHealthChangedEvent e)
- {
- UpdateUI(); // UI职责
- PlayAudio(); // 音频职责
- SaveStatistics(); // 存档职责
- UpdateAchievements(); // 成就系统职责
- // 一个事件处理器承担太多职责
- }
-}
-```
-
-## 模块化架构
-
-### 1. 模块边界清晰
-
-```csharp
-// ✅ 好的做法:清晰的模块边界
-public class AudioModule : AbstractModule
-{
- // 模块只负责音频相关的功能
- public override void Install(IArchitecture architecture)
- {
- architecture.RegisterSystem(new AudioSystem());
- architecture.RegisterSystem(new MusicSystem());
- architecture.RegisterUtility(new AudioUtility());
- }
-}
-
-public class InputModule : AbstractModule
-{
- // 模块只负责输入相关的功能
- public override void Install(IArchitecture architecture)
- {
- architecture.RegisterSystem(new InputSystem());
- architecture.RegisterSystem(new InputMappingSystem());
- architecture.RegisterUtility(new InputUtility());
- }
-}
-
-public class UIModule : AbstractModule
-{
- // 模块只负责UI相关的功能
- public override void Install(IArchitecture architecture)
- {
- architecture.RegisterSystem(new UISystem());
- architecture.RegisterSystem(new HUDSystem());
- architecture.RegisterSystem(new MenuSystem());
- architecture.RegisterUtility(new UIUtility());
- }
-}
-
-// ❌ 避免:模块职责混乱
-public class GameModule : AbstractModule
-{
- public override void Install(IArchitecture architecture)
- {
- // 一个模块包含所有功能
- architecture.RegisterSystem(new AudioSystem()); // 音频
- architecture.RegisterSystem(new InputSystem()); // 输入
- architecture.RegisterSystem(new UISystem()); // UI
- architecture.RegisterSystem(new CombatSystem()); // 战斗
- architecture.RegisterSystem(new InventorySystem()); // 背包
- architecture.RegisterSystem(new QuestSystem()); // 任务
- // 模块过于庞大,难以维护
- }
-}
-```
-
-### 2. 模块间通信
-
-```csharp
-// ✅ 好的做法:通过事件进行模块间通信
-public class AudioModule : AbstractModule
-{
- public override void Install(IArchitecture architecture)
- {
- architecture.RegisterSystem(new AudioSystem());
- }
-}
-
-public class AudioSystem : AbstractSystem
-{
- protected override void OnInit()
- {
- // 监听其他模块发送的事件
- this.RegisterEvent(OnPlayerAttack);
- this.RegisterEvent(OnPlayerDied);
- this.RegisterEvent(OnWeaponEquipped);
- }
-
- private void OnPlayerAttack(PlayerAttackEvent e)
- {
- PlayAttackSound(e.WeaponType);
- }
-
- private void OnPlayerDied(PlayerDiedEvent e)
- {
- PlayDeathSound();
- }
-
- private void OnWeaponEquipped(WeaponEquippedEvent e)
- {
- PlayEquipSound(e.WeaponType);
- }
-}
-
-public class CombatModule : AbstractModule
-{
- public override void Install(IArchitecture architecture)
- {
- architecture.RegisterSystem(new CombatSystem());
- }
-}
-
-public class CombatSystem : AbstractSystem
-{
- protected override void OnInit()
- {
- this.RegisterEvent(OnAttackInput);
- }
-
- private void OnAttackInput(AttackInputEvent e)
- {
- ProcessAttack(e);
-
- // 发送事件通知其他模块
- SendEvent(new PlayerAttackEvent {
- PlayerId = e.PlayerId,
- WeaponType = GetPlayerWeaponType(e.PlayerId)
- });
- }
-}
-
-// ❌ 避免:模块间直接依赖
-public class CombatSystem : AbstractSystem
-{
- private AudioSystem _audioSystem; // 直接依赖其他模块
-
- protected override void OnInit()
- {
- // 直接获取其他模块的系统
- _audioSystem = GetSystem();
- }
-
- private void OnAttackInput(AttackInputEvent e)
- {
- ProcessAttack(e);
-
- // 直接调用其他模块的方法
- _audioSystem.PlayAttackSound(weaponType);
- }
-}
-```
-
-## 错误处理策略
-
-### 1. 异常处理层次
-
-```csharp
-// ✅ 好的做法:分层异常处理
-public class GameApplicationException : Exception
-{
- public string ErrorCode { get; }
- public Dictionary Context { get; }
-
- public GameApplicationException(string message, string errorCode,
- Dictionary context = null, Exception innerException = null)
- : base(message, innerException)
- {
- ErrorCode = errorCode;
- Context = context ?? new Dictionary();
- }
-}
-
-public class PlayerException : GameApplicationException
-{
- public PlayerException(string message, string errorCode,
- Dictionary context = null, Exception innerException = null)
- : base(message, errorCode, context, innerException)
- {
- }
-}
-
-public class InventoryException : GameApplicationException
-{
- public InventoryException(string message, string errorCode,
- Dictionary context = null, Exception innerException = null)
- : base(message, errorCode, context, innerException)
- {
- }
-}
-
-// 在系统中的使用
-public class PlayerInventorySystem : AbstractSystem
-{
- public void AddItem(string playerId, Item item)
- {
- try
- {
- ValidateItem(item);
- CheckInventorySpace(playerId, item);
-
- AddItemToInventory(playerId, item);
-
- SendEvent(new ItemAddedEvent { PlayerId = playerId, Item = item });
- }
- catch (ItemValidationException ex)
- {
- throw new InventoryException(
- $"Failed to add item {item.Id} to player {playerId}",
- "ITEM_VALIDATION_FAILED",
- new Dictionary
- {
- ["playerId"] = playerId,
- ["itemId"] = item.Id,
- ["validationError"] = ex.Message
- },
- ex
- );
- }
- catch (InventoryFullException ex)
- {
- throw new InventoryException(
- $"Player {playerId} inventory is full",
- "INVENTORY_FULL",
- new Dictionary
- {
- ["playerId"] = playerId,
- ["itemId"] = item.Id,
- ["maxSlots"] = ex.MaxSlots,
- ["currentSlots"] = ex.CurrentSlots
- },
- ex
- );
- }
- catch (Exception ex)
- {
- // 捕获未知异常并包装
- throw new InventoryException(
- $"Unexpected error adding item {item.Id} to player {playerId}",
- "UNKNOWN_ERROR",
- new Dictionary
- {
- ["playerId"] = playerId,
- ["itemId"] = item.Id,
- ["originalError"] = ex.Message
- },
- ex
- );
- }
- }
-
- private void ValidateItem(Item item)
- {
- if (item == null)
- throw new ItemValidationException("Item cannot be null");
-
- if (string.IsNullOrEmpty(item.Id))
- throw new ItemValidationException("Item ID cannot be empty");
-
- if (item.StackSize <= 0)
- throw new ItemValidationException("Item stack size must be positive");
- }
-
- private void CheckInventorySpace(string playerId, Item item)
- {
- var inventory = GetPlayerInventory(playerId);
- var requiredSpace = CalculateRequiredSpace(item);
-
- if (inventory.FreeSpace < requiredSpace)
- {
- throw new InventoryFullException(
- inventory.FreeSpace,
- inventory.MaxSlots
- );
- }
- }
-}
-```
-
-### 2. 错误恢复策略
-
-```csharp
-// ✅ 好的做法:优雅的错误恢复
-public class SaveSystem : AbstractSystem
-{
- private readonly IStorage _primaryStorage;
- private readonly IStorage _backupStorage;
-
- public SaveSystem(IStorage primaryStorage, IStorage backupStorage = null)
- {
- _primaryStorage = primaryStorage;
- _backupStorage = backupStorage ?? new LocalStorage("backup");
- }
-
- public async Task LoadSaveDataAsync(string saveId)
- {
- try
- {
- // 尝试从主存储加载
- return await _primaryStorage.ReadAsync(saveId);
- }
- catch (StorageException ex)
- {
- Logger.Warning($"Failed to load from primary storage: {ex.Message}");
-
- try
- {
- // 尝试从备份存储加载
- var backupData = await _backupStorage.ReadAsync(saveId);
- Logger.Info($"Successfully loaded from backup storage: {saveId}");
-
- // 恢复到主存储
- await _primaryStorage.WriteAsync(saveId, backupData);
-
- return backupData;
- }
- catch (Exception backupEx)
- {
- Logger.Error($"Failed to load from backup storage: {backupEx.Message}");
-
- // 返回默认存档数据
- return GetDefaultSaveData();
- }
- }
- }
-
- private SaveData GetDefaultSaveData()
- {
- Logger.Warning("Returning default save data due to loading failures");
- return new SaveData
- {
- PlayerId = "default",
- Level = 1,
- Health = 100,
- Position = Vector3.Zero,
- CreatedAt = DateTime.UtcNow
- };
- }
-}
-
-// ❌ 避免:粗暴的错误处理
-public class SaveSystem : AbstractSystem
-{
- public async Task LoadSaveDataAsync(string saveId)
- {
- try
- {
- return await _storage.ReadAsync(saveId);
- }
- catch (Exception ex)
- {
- // 直接抛出异常,不提供恢复机制
- throw new Exception($"Failed to load save: {ex.Message}", ex);
- }
- }
-}
-```
-
-## 测试策略
-
-### 1. 可测试的架构设计
-
-```csharp
-// ✅ 好的做法:可测试的架构
-public interface IPlayerMovementService
-{
- void MovePlayer(string playerId, Vector2 direction);
- bool CanPlayerMove(string playerId);
-}
-
-public class PlayerMovementService : IPlayerMovementService
-{
- private readonly IPlayerRepository _playerRepository;
- private readonly ICollisionService _collisionService;
- private readonly IMapService _mapService;
-
- public PlayerMovementService(
- IPlayerRepository playerRepository,
- ICollisionService collisionService,
- IMapService mapService)
- {
- _playerRepository = playerRepository;
- _collisionService = collisionService;
- _mapService = mapService;
- }
-
- public void MovePlayer(string playerId, Vector2 direction)
- {
- if (!CanPlayerMove(playerId))
- return;
-
- var player = _playerRepository.GetById(playerId);
- var newPosition = player.Position + direction * player.Speed;
-
- if (_collisionService.CanMoveTo(newPosition))
- {
- player.Position = newPosition;
- _playerRepository.Update(player);
- }
- }
-
- public bool CanPlayerMove(string playerId)
- {
- var player = _playerRepository.GetById(playerId);
- return player != null && player.IsAlive && !player.IsStunned;
- }
-}
-
-// 测试代码
-[TestFixture]
-public class PlayerMovementServiceTests
-{
- private Mock _mockPlayerRepository;
- private Mock _mockCollisionService;
- private Mock _mockMapService;
- private PlayerMovementService _movementService;
-
- [SetUp]
- public void Setup()
- {
- _mockPlayerRepository = new Mock();
- _mockCollisionService = new Mock();
- _mockMapService = new Mock();
-
- _movementService = new PlayerMovementService(
- _mockPlayerRepository.Object,
- _mockCollisionService.Object,
- _mockMapService.Object
- );
- }
-
- [Test]
- public void MovePlayer_ValidMovement_ShouldUpdatePlayerPosition()
- {
- // Arrange
- var playerId = "player1";
- var player = new Player { Id = playerId, Position = Vector2.Zero, Speed = 5.0f };
- var direction = Vector2.Right;
-
- _mockPlayerRepository.Setup(r => r.GetById(playerId)).Returns(player);
- _mockCollisionService.Setup(c => c.CanMoveTo(It.IsAny())).Returns(true);
-
- // Act
- _movementService.MovePlayer(playerId, direction);
-
- // Assert
- _mockPlayerRepository.Verify(r => r.Update(It.Is(p => p.Position == Vector2.Right * 5.0f)), Times.Once);
- }
-
- [Test]
- public void MovePlayer_CollisionBlocked_ShouldNotUpdatePlayerPosition()
- {
- // Arrange
- var playerId = "player1";
- var player = new Player { Id = playerId, Position = Vector2.Zero, Speed = 5.0f };
- var direction = Vector2.Right;
-
- _mockPlayerRepository.Setup(r => r.GetById(playerId)).Returns(player);
- _mockCollisionService.Setup(c => c.CanMoveTo(It.IsAny())).Returns(false);
-
- // Act
- _movementService.MovePlayer(playerId, direction);
-
- // Assert
- _mockPlayerRepository.Verify(r => r.Update(It.IsAny()), Times.Never);
- }
-}
-
-// ❌ 避免:难以测试的设计
-public class PlayerMovementSystem : AbstractSystem
-{
- protected override void OnInit()
- {
- this.RegisterEvent(OnMovementInput);
- }
-
- private void OnMovementInput(MovementInputEvent e)
- {
- var player = GetModel(); // 依赖架构,难以测试
- var newPosition = player.Position + e.Direction * player.Speed;
-
- if (CanMoveTo(newPosition)) // 私有方法,难以直接测试
- {
- player.Position = newPosition;
- }
- }
-
- private bool CanMoveTo(Vector2 position)
- {
- // 复杂的碰撞检测逻辑,难以测试
- return true;
- }
-}
-```
-
-## 重构指南
-
-### 1. 识别代码异味
-
-```csharp
-// ❌ 代码异味:长方法、重复代码、上帝类
-public class GameManager : Node
-{
- public void ProcessPlayerInput(InputEvent @event)
- {
- // 长方法 - 做太多事情
- if (@event is InputEventKey keyEvent && keyEvent.Pressed)
- {
- switch (keyEvent.Keycode)
- {
- case Key.W:
- MovePlayer(Vector2.Up);
- PlayFootstepSound();
- UpdatePlayerAnimation("walk_up");
- CheckPlayerCollisions();
- UpdateCameraPosition();
- SavePlayerPosition();
- break;
- case Key.S:
- MovePlayer(Vector2.Down);
- PlayFootstepSound();
- UpdatePlayerAnimation("walk_down");
- CheckPlayerCollisions();
- UpdateCameraPosition();
- SavePlayerPosition();
- break;
- // 重复代码
- }
- }
- }
-
- private void MovePlayer(Vector2 direction)
- {
- Player.Position += direction * Player.Speed;
- }
-
- private void PlayFootstepSound()
- {
- AudioPlayer.Play("footstep.wav");
- }
-
- // ... 更多方法,类过于庞大
-}
-
-// ✅ 重构后:职责分离
-public class PlayerInputController : AbstractSystem
-{
- protected override void OnInit()
- {
- this.RegisterEvent(OnInput);
- }
-
- private void OnInput(InputEvent e)
- {
- if (e is InputEventKey keyEvent && keyEvent.Pressed)
- {
- var direction = GetDirectionFromKey(keyEvent.Keycode);
- if (direction != Vector2.Zero)
- {
- SendEvent(new PlayerMoveEvent { Direction = direction });
- }
- }
- }
-
- private Vector2 GetDirectionFromKey(Key keycode)
- {
- return keycode switch
- {
- Key.W => Vector2.Up,
- Key.S => Vector2.Down,
- Key.A => Vector2.Left,
- Key.D => Vector2.Right,
- _ => Vector2.Zero
- };
- }
-}
-
-public class PlayerMovementSystem : AbstractSystem
-{
- protected override void OnInit()
- {
- this.RegisterEvent(OnPlayerMove);
- }
-
- private void OnPlayerMove(PlayerMoveEvent e)
- {
- var playerModel = GetModel();
- var newPosition = playerModel.Position + e.Direction * playerModel.Speed;
-
- if (CanMoveTo(newPosition))
- {
- playerModel.Position = newPosition;
- SendEvent(new PlayerMovedEvent { NewPosition = newPosition });
- }
- }
-
- private bool CanMoveTo(Vector2 position)
- {
- var collisionService = GetUtility();
- return collisionService.CanMoveTo(position);
- }
-}
-
-public class AudioSystem : AbstractSystem
-{
- protected override void OnInit()
- {
- this.RegisterEvent(OnPlayerMoved);
- }
-
- private void OnPlayerMoved(PlayerMovedEvent e)
- {
- PlayFootstepSound();
- }
-
- private void PlayFootstepSound()
- {
- var audioUtility = GetUtility();
- audioUtility.PlaySound("footstep.wav");
- }
-}
-
-public class AnimationSystem : AbstractSystem
-{
- protected override void OnInit()
- {
- this.RegisterEvent(OnPlayerMoved);
- }
-
- private void OnPlayerMoved(PlayerMovedEvent e)
- {
- var animationName = GetAnimationNameFromDirection(e.Direction);
- SendEvent(new PlayAnimationEvent { AnimationName = animationName });
- }
-
- private string GetAnimationNameFromDirection(Vector2 direction)
- {
- if (direction == Vector2.Up) return "walk_up";
- if (direction == Vector2.Down) return "walk_down";
- if (direction == Vector2.Left) return "walk_left";
- if (direction == Vector2.Right) return "walk_right";
- return "idle";
- }
-}
-```
-
-### 2. 渐进式重构
-
-```csharp
-// 第一步:提取重复代码
-public class PlayerController : Node
-{
- public void ProcessInput(InputEvent @event)
- {
- if (@event is InputEventKey keyEvent && keyEvent.Pressed)
- {
- Vector2 direction;
- switch (keyEvent.Keycode)
- {
- case Key.W:
- direction = Vector2.Up;
- break;
- case Key.S:
- direction = Vector2.Down;
- break;
- case Key.A:
- direction = Vector2.Left;
- break;
- case Key.D:
- direction = Vector2.Right;
- break;
- default:
- return;
- }
-
- MovePlayer(direction);
- }
- }
-}
-
-// 第二步:提取方法
-public class PlayerController : Node
-{
- public void ProcessInput(InputEvent @event)
- {
- if (@event is InputEventKey keyEvent && keyEvent.Pressed)
- {
- var direction = GetDirectionFromKey(keyEvent.Keycode);
- if (direction != Vector2.Zero)
- {
- MovePlayer(direction);
- }
- }
- }
-
- private Vector2 GetDirectionFromKey(Key keycode)
- {
- return keycode switch
- {
- Key.W => Vector2.Up,
- Key.S => Vector2.Down,
- Key.A => Vector2.Left,
- Key.D => Vector2.Right,
- _ => Vector2.Zero
- };
- }
-}
-
-// 第三步:引入系统和事件
-public class PlayerController : AbstractSystem
-{
- protected override void OnInit()
- {
- this.RegisterEvent(OnInput);
- }
-
- private void OnInput(InputEvent e)
- {
- if (e is InputEventKey keyEvent && keyEvent.Pressed)
- {
- var direction = GetDirectionFromKey(keyEvent.Keycode);
- if (direction != Vector2.Zero)
- {
- SendEvent(new PlayerMoveEvent { Direction = direction });
- }
- }
- }
-
- private Vector2 GetDirectionFromKey(Key keycode)
- {
- return keycode switch
- {
- Key.W => Vector2.Up,
- Key.S => Vector2.Down,
- Key.A => Vector2.Left,
- Key.D => Vector2.Right,
- _ => Vector2.Zero
- };
- }
-}
-```
-
----
-
-## 模式选择与组合
-
-### 何时使用哪种模式?
-
-#### 小型项目(原型、Demo)
-
-```csharp
-// 推荐组合:MVC + 事件驱动 + 服务定位器
-public class SimpleGameArchitecture : Architecture
-{
- protected override void Init()
- {
- // Model
- RegisterModel(new PlayerModel());
- RegisterModel(new GameModel());
-
- // System
- RegisterSystem(new GameplaySystem());
- RegisterSystem(new AudioSystem());
-
- // 使用服务定位器模式
- // Controller 通过 this.GetModel/GetSystem 获取服务
- }
-}
-```
-
-**优势**:
-
-- 快速开发
-- 代码简洁
-- 易于理解
-
-#### 中型项目(独立游戏)
-
-```csharp
-// 推荐组合:MVC + MVVM + 命令/查询 + 事件驱动 + 依赖注入
-public class GameArchitecture : Architecture
-{
- protected override void Init()
- {
- // 注册 Utility(依赖注入)
- RegisterUtility<IStorageService>(new LocalStorageService());
- RegisterUtility<IAudioService>(new GodotAudioService());
-
- // 注册 Model(MVVM)
- RegisterModel(new PlayerModel());
- RegisterModel(new PlayerViewModel());
-
- // 注册 System(命令/查询处理)
- RegisterSystem(new CombatSystem());
- RegisterSystem(new InventorySystem());
-
- // 状态机
- var stateMachine = new StateMachineSystem();
- stateMachine
- .Register(new MenuState())
- .Register(new GameplayState());
- RegisterSystem<IStateMachineSystem>(stateMachine);
- }
-}
-```
-
-**优势**:
-
-- 职责清晰
-- 易于测试
-- 支持团队协作
-
-#### 大型项目(商业游戏)
-
-```csharp
-// 推荐组合:所有模式 + 模块化架构
-public class GameArchitecture : Architecture
-{
- protected override void Init()
- {
- // 模块化安装
- InstallModule(new CoreModule());
- InstallModule(new AudioModule());
- InstallModule(new NetworkModule());
- InstallModule(new UIModule());
- InstallModule(new GameplayModule());
- }
-}
-
-// 核心模块
-public class CoreModule : IArchitectureModule
-{
- public void Install(IArchitecture architecture)
- {
- // 依赖注入
- architecture.RegisterUtility<IStorageService>(new CloudStorageService());
- architecture.RegisterUtility<IAnalyticsService>(new AnalyticsService());
-
- // 对象池
- architecture.RegisterSystem(new BulletPoolSystem());
- architecture.RegisterSystem(new ParticlePoolSystem());
- }
-}
-
-// 游戏玩法模块
-public class GameplayModule : IArchitectureModule
-{
- public void Install(IArchitecture architecture)
- {
- // Model
- architecture.RegisterModel(new PlayerModel());
- architecture.RegisterModel(new EnemyModel());
-
- // System(使用命令/查询模式)
- architecture.RegisterSystem(new CombatSystem());
- architecture.RegisterSystem(new MovementSystem());
-
- // 状态机
- var stateMachine = new StateMachineSystem();
- stateMachine
- .Register(new MenuState())
- .Register(new LoadingState())
- .Register(new GameplayState())
- .Register(new PauseState())
- .Register(new GameOverState());
- architecture.RegisterSystem<IStateMachineSystem>(stateMachine);
- }
-}
-```
-
-**优势**:
-
-- 高度模块化
-- 易于维护和扩展
-- 支持大型团队
-- 完善的测试覆盖
-
-### 模式组合示例
-
-#### 组合 1:MVVM + 命令模式
-
-```csharp
-// ViewModel
-public class ShopViewModel : AbstractModel
-{
- public BindableProperty<int> PlayerGold { get; } = new(1000);
- public BindableProperty<bool> CanBuy { get; } = new(true);
- public BindableProperty<string> StatusMessage { get; } = new("");
-
- protected override void OnInit()
- {
- // 监听购买事件
- this.RegisterEvent<ItemPurchasedEvent>(OnItemPurchased);
- this.RegisterEvent<InsufficientGoldEvent>(OnInsufficientGold);
-
- // 监听金币变化
- PlayerGold.Register(gold =>
- {
- CanBuy.Value = gold >= 100;
- });
- }
-
- private void OnItemPurchased(ItemPurchasedEvent e)
- {
- PlayerGold.Value -= e.Cost;
- StatusMessage.Value = $"购买成功:{e.ItemName}";
- }
-
- private void OnInsufficientGold(InsufficientGoldEvent e)
- {
- StatusMessage.Value = "金币不足!";
- }
-}
-
-// View
-public class ShopView : Control
-{
- private ShopViewModel _viewModel;
-
- public override void _Ready()
- {
- _viewModel = GetModel<ShopViewModel>();
-
- // 数据绑定
- _viewModel.PlayerGold.Register(gold =>
- {
- GetNode<Label>("GoldLabel").Text = $"金币:{gold}";
- });
-
- _viewModel.CanBuy.Register(canBuy =>
- {
- GetNode<Button>("BuyButton").Disabled = !canBuy;
- });
-
- _viewModel.StatusMessage.Register(msg =>
- {
- GetNode<Label>("StatusLabel").Text = msg;
- });
- }
-
- private void OnBuyButtonPressed()
- {
- // 发送命令
- this.SendCommand(new BuyItemCommand
- {
- Input = new BuyItemInput { ItemId = "sword_01" }
- });
- }
-}
-```
-
-#### 组合 2:状态模式 + 对象池
-
-```csharp
-// 游戏状态使用对象池
-public class GameplayState : ContextAwareStateBase
-{
- private BulletPoolSystem _bulletPool;
- private ParticlePoolSystem _particlePool;
-
- public override void OnEnter(IState from)
- {
- // 获取对象池
- _bulletPool = this.GetSystem<BulletPoolSystem>();
- _particlePool = this.GetSystem<ParticlePoolSystem>();
-
- // 预热对象池
- _bulletPool.PrewarmPool(100);
- _particlePool.PrewarmPool(200);
-
- // 注册事件
- this.RegisterEvent<FireWeaponEvent>(OnFireWeapon);
- }
-
- private void OnFireWeapon(FireWeaponEvent e)
- {
- // 从池中获取子弹
- var bullet = _bulletPool.Spawn();
- bullet.Position = e.Position;
- bullet.Direction = e.Direction;
-
- // 生成粒子效果
- var particle = _particlePool.Spawn();
- particle.Position = e.Position;
- }
-
- public override void OnExit(IState to)
- {
- // 回收所有对象
- _bulletPool.RecycleAll();
- _particlePool.RecycleAll();
- }
-}
-```
-
-#### 组合 3:事件驱动 + 查询模式
-
-```csharp
-// 成就系统:监听事件,使用查询验证条件
-public class AchievementSystem : AbstractSystem
-{
- protected override void OnInit()
- {
- this.RegisterEvent<EnemyKilledEvent>(OnEnemyKilled);
- this.RegisterEvent<LevelCompletedEvent>(OnLevelCompleted);
- }
-
- private void OnEnemyKilled(EnemyKilledEvent e)
- {
- // 查询击杀总数
- var query = new GetTotalKillsQuery { Input = new EmptyQueryInput() };
- var totalKills = this.SendQuery(query);
-
- // 检查成就
- if (totalKills == 100)
- {
- UnlockAchievement("kill_100_enemies");
- }
- }
-
- private void OnLevelCompleted(LevelCompletedEvent e)
- {
- // 查询是否满足完美通关条件
- var query = new IsPerfectClearQuery
- {
- Input = new IsPerfectClearInput { LevelId = e.LevelId }
- };
- var isPerfect = this.SendQuery(query);
-
- if (isPerfect)
- {
- UnlockAchievement($"perfect_clear_level_{e.LevelId}");
- }
- }
-}
-```
-
-### 模式选择决策树
-
-```
-需要管理游戏状态?
-├─ 是 → 使用状态模式
-└─ 否 → 继续
-
-需要频繁创建/销毁对象?
-├─ 是 → 使用对象池模式
-└─ 否 → 继续
-
-需要解耦组件通信?
-├─ 是 → 使用事件驱动模式
-└─ 否 → 继续
-
-需要封装操作?
-├─ 是 → 使用命令模式
-└─ 否 → 继续
-
-需要分离读写操作?
-├─ 是 → 使用查询模式(CQRS)
-└─ 否 → 继续
-
-需要数据绑定和响应式 UI?
-├─ 是 → 使用 MVVM 模式
-└─ 否 → 使用 MVC 模式
-
-需要管理依赖?
-├─ 大型项目 → 使用依赖注入
-└─ 小型项目 → 使用服务定位器
-```
-
-## 常见问题
-
-### Q1: 应该使用 MVC 还是 MVVM?
-
-**A**: 取决于项目需求:
-
-- **使用 MVC**:
- - 简单的 UI 更新
- - 不需要复杂的数据绑定
- - 快速原型开发
-
-- **使用 MVVM**:
- - 复杂的数据驱动 UI
- - 需要自动更新界面
- - 大量计算属性
-
-**推荐**:可以混合使用,简单界面用 MVC,复杂界面用 MVVM。
-
-### Q2: 命令模式和查询模式有什么区别?
-
-**A**:
-
-| 特性 | 命令模式 | 查询模式 |
-|---------|----------------|---------------------|
-| **目的** | 修改状态 | 读取数据 |
-| **返回值** | 可选 | 必须有 |
-| **副作用** | 有 | 无 |
-| **示例** | BuyItemCommand | GetPlayerStatsQuery |
-
-**原则**:命令改变状态,查询读取状态,两者不混用。
-
-### Q3: 何时使用事件,何时使用命令?
-
-**A**:
-
-- **使用事件**:
- - 通知状态变化
- - 一对多通信
- - 跨模块通信
- - 不关心处理结果
-
-- **使用命令**:
- - 执行具体操作
- - 需要封装逻辑
- - 需要撤销/重做
- - 需要返回结果
-
-**示例**:
-
-```csharp
-// 使用命令执行操作
-this.SendCommand(new BuyItemCommand());
-
-// 使用事件通知结果
-this.SendEvent(new ItemPurchasedEvent());
-```
-
-### Q4: 依赖注入和服务定位器哪个更好?
-
-**A**:
-
-- **依赖注入**:
- - ✅ 依赖关系明确
- - ✅ 易于测试
- - ✅ 编译时检查
- - ❌ 配置复杂
-
-- **服务定位器**:
- - ✅ 简单直接
- - ✅ 易于使用
- - ❌ 依赖隐式
- - ❌ 难以测试
-
-**推荐**:
-
-- 小项目:服务定位器
-- 大项目:依赖注入
-- 混合使用:核心服务用依赖注入,辅助服务用服务定位器
-
-### Q5: 对象池适合哪些场景?
-
-**A**:
-
-**适合**:
-
-- 频繁创建/销毁的对象(子弹、粒子)
-- 创建成本高的对象(网络连接)
-- 需要稳定帧率的场景
-
-**不适合**:
-
-- 创建频率低的对象
-- 对象状态复杂难以重置
-- 内存受限的场景
-
-**示例**:
-
-```csharp
-// ✅ 适合使用对象池
-- 子弹、导弹
-- 粒子效果
-- UI 元素(列表项)
-- 音效播放器
-
-// ❌ 不适合使用对象池
-- 玩家角色
-- 关卡数据
-- 配置对象
-```
-
-### Q6: 状态机和简单的 if-else 有什么区别?
-
-**A**:
-
-**简单 if-else**:
-
-```csharp
-// ❌ 难以维护
-public void Update()
-{
- if (gameState == GameState.Menu)
- {
- UpdateMenu();
- }
- else if (gameState == GameState.Playing)
- {
- UpdateGameplay();
- }
- else if (gameState == GameState.Paused)
- {
- UpdatePause();
- }
- // 状态逻辑分散,难以管理
-}
-```
-
-**状态机**:
-
-```csharp
-// ✅ 清晰易维护
-public class MenuState : ContextAwareStateBase
-{
- public override void OnEnter(IState from)
- {
- // 进入菜单的所有逻辑集中在这里
- }
-
- public override void OnExit(IState to)
- {
- // 退出菜单的所有逻辑集中在这里
- }
-}
-```
-
-**优势**:
-
-- 状态逻辑封装
-- 易于添加新状态
-- 支持状态转换验证
-- 支持状态历史
-
-### Q7: 如何避免过度设计?
-
-**A**:
-
-**原则**:
-
-1. **从简单开始**:先用最简单的方案
-2. **按需重构**:遇到问题再优化
-3. **YAGNI 原则**:You Aren't Gonna Need It
-
-**示例**:
-
-```csharp
-// 第一版:简单直接
-public class Player
-{
- public int Health = 100;
-}
-
-// 第二版:需要通知时添加事件
-public class Player
-{
- private int _health = 100;
- public int Health
- {
- get => _health;
- set
- {
- _health = value;
- OnHealthChanged?.Invoke(value);
- }
- }
- public event Action<int> OnHealthChanged;
-}
-
-// 第三版:需要更多功能时使用 BindableProperty
-public class PlayerModel : AbstractModel
-{
- public BindableProperty<int> Health { get; } = new(100);
-}
-```
-
-### Q8: 如何在现有项目中引入这些模式?
-
-**A**:
-
-**渐进式重构**:
-
-1. **第一步:引入事件系统**
- ```csharp
- // 替换直接调用为事件
- // 之前:uiManager.UpdateHealth(health);
- // 之后:SendEvent(new HealthChangedEvent { Health = health });
- ```
-
-2. **第二步:提取 Model**
- ```csharp
- // 将数据从各处集中到 Model
- public class PlayerModel : AbstractModel
- {
- public BindableProperty<int> Health { get; } = new(100);
- }
- ```
-
-3. **第三步:引入命令模式**
- ```csharp
- // 封装操作为命令
- public class HealPlayerCommand : AbstractCommand
- {
- protected override void OnExecute()
- {
- var player = this.GetModel<PlayerModel>();
- player.Health.Value = player.MaxHealth.Value;
- }
- }
- ```
-
-4. **第四步:添加查询模式**
- ```csharp
- // 分离读操作
- public class GetPlayerStatsQuery : AbstractQuery<PlayerStats>
- {
- protected override PlayerStats OnDo()
- {
- // 查询逻辑
- }
- }
- ```
-
-### Q9: 性能会受到影响吗?
-
-**A**:
-
-**影响很小**:
-
-- 事件系统:微秒级开销
-- 命令/查询:几乎无开销
-- IoC 容器:字典查找,O(1)
-
-**优化建议**:
-
-1. **避免频繁事件**:不要每帧发送事件
-2. **缓存查询结果**:复杂查询结果可以缓存
-3. **使用对象池**:减少 GC 压力
-4. **批量操作**:合并多个小操作
-
-**性能对比**:
-
-```csharp
-// 直接调用:~1ns
-player.Health = 100;
-
-// 通过命令:~100ns
-SendCommand(new SetHealthCommand { Health = 100 });
-
-// 差异可以忽略不计,但带来了更好的架构
-```
-
-### Q10: 如何测试使用这些模式的代码?
-
-**A**:
-
-**单元测试示例**:
-
-```csharp
-[Test]
-public void BuyItemCommand_InsufficientGold_ShouldNotBuyItem()
-{
- // Arrange
- var architecture = new TestArchitecture();
- var playerModel = new PlayerModel();
- playerModel.Gold.Value = 50; // 金币不足
- architecture.RegisterModel(playerModel);
-
- var command = new BuyItemCommand
- {
- Input = new BuyItemInput { ItemId = "sword", Price = 100 }
- };
- command.SetArchitecture(architecture);
-
- // Act
- command.Execute();
-
- // Assert
- Assert.AreEqual(50, playerModel.Gold.Value); // 金币未变化
-}
-
-[Test]
-public void GetPlayerStatsQuery_ShouldReturnCorrectStats()
-{
- // Arrange
- var architecture = new TestArchitecture();
- var playerModel = new PlayerModel();
- playerModel.Level.Value = 10;
- playerModel.Health.Value = 80;
- architecture.RegisterModel(playerModel);
-
- var query = new GetPlayerStatsQuery();
- query.SetArchitecture(architecture);
-
- // Act
- var stats = query.Do();
-
- // Assert
- Assert.AreEqual(10, stats.Level);
- Assert.AreEqual(80, stats.Health);
-}
-```
-
----
-
-## 总结
-
-遵循这些架构模式最佳实践,你将能够构建:
-
-- ✅ **清晰的代码结构** - 易于理解和维护
-- ✅ **松耦合的组件** - 便于测试和扩展
-- ✅ **可重用的模块** - 提高开发效率
-- ✅ **健壮的错误处理** - 提高系统稳定性
-- ✅ **完善的测试覆盖** - 保证代码质量
-
-### 关键要点
-
-1. **从简单开始**:不要过度设计,按需添加模式
-2. **理解每个模式的适用场景**:选择合适的模式解决问题
-3. **模式可以组合使用**:发挥各自优势
-4. **持续重构**:随着项目发展优化架构
-5. **注重可测试性**:好的架构应该易于测试
-
-### 推荐学习路径
-
-1. **入门**:MVC + 事件驱动
-2. **进阶**:命令模式 + 查询模式 + MVVM
-3. **高级**:状态模式 + 对象池 + 依赖注入
-4. **专家**:模块化架构 + 所有模式组合
-
-### 相关资源
-
-- [架构核心文档](/zh-CN/core/architecture)
-- [命令模式文档](/zh-CN/core/command)
-- [查询模式文档](/zh-CN/core/query)
-- [事件系统文档](/zh-CN/core/events)
-- [状态机文档](/zh-CN/core/state-machine)
-- [IoC 容器文档](/zh-CN/core/ioc)
-
-记住,好的架构不是一蹴而就的,需要持续的学习、实践和改进。
-
----
-
-**文档版本**: 2.0.0
-**最后更新**: 2026-03-07
+# 架构设计模式指南
+
+> 全面介绍 GFramework 中的架构设计模式,帮助你构建清晰、可维护、可扩展的游戏架构。
+
+## 📋 目录
+
+- [概述](#概述)
+- [MVC 模式](#mvc-模式)
+- [MVVM 模式](#mvvm-模式)
+- [命令模式](#命令模式)
+- [查询模式](#查询模式)
+- [事件驱动模式](#事件驱动模式)
+- [依赖注入模式](#依赖注入模式)
+- [服务定位器模式](#服务定位器模式)
+- [对象池模式](#对象池模式)
+- [状态模式](#状态模式)
+- [设计原则](#设计原则)
+- [架构分层](#架构分层)
+- [依赖管理](#依赖管理)
+- [事件系统设计](#事件系统设计)
+- [模块化架构](#模块化架构)
+- [错误处理策略](#错误处理策略)
+- [测试策略](#测试策略)
+- [重构指南](#重构指南)
+- [模式选择与组合](#模式选择与组合)
+- [常见问题](#常见问题)
+
+## 概述
+
+架构设计模式是经过验证的解决方案,用于解决软件开发中的常见问题。GFramework 内置了多种设计模式,帮助你构建高质量的游戏应用。
+
+### 为什么需要架构设计模式?
+
+1. **提高代码质量**:遵循最佳实践,减少 bug
+2. **增强可维护性**:清晰的结构,易于理解和修改
+3. **促进团队协作**:统一的代码风格和架构
+4. **提升可扩展性**:轻松添加新功能
+5. **简化测试**:解耦的组件更容易测试
+
+### GFramework 支持的核心模式
+
+| 模式 | 用途 | 核心组件 |
+|-----------|--------------|-------------------------|
+| **MVC** | 分离数据、视图和控制逻辑 | Model, Controller |
+| **MVVM** | 数据绑定和响应式 UI | Model, BindableProperty |
+| **命令模式** | 封装操作请求 | ICommand, CommandBus |
+| **查询模式** | 分离读操作 | IQuery, QueryBus |
+| **事件驱动** | 松耦合通信 | IEventBus, Event |
+| **依赖注入** | 控制反转 | IIocContainer |
+| **服务定位器** | 服务查找 | Architecture.GetSystem |
+| **对象池** | 对象复用 | IObjectPoolSystem |
+| **状态模式** | 状态管理 | IStateMachine |
+
+## MVC 模式
+
+### 概念
+
+MVC(Model-View-Controller)是一种将应用程序分为三个核心组件的架构模式:
+
+- **Model(模型)**:管理数据和业务逻辑
+- **View(视图)**:显示数据给用户
+- **Controller(控制器)**:处理用户输入,协调 Model 和 View
+
+### 在 GFramework 中的实现
+
+```csharp
+// Model - 数据层
+public class PlayerModel : AbstractModel
+{
+ public BindableProperty<int> Health { get; } = new(100);
+ public BindableProperty<int> Score { get; } = new(0);
+ public BindableProperty<string> Name { get; } = new("Player");
+
+ protected override void OnInit()
+ {
+ // 监听数据变化
+ Health.Register(newHealth =>
+ {
+ if (newHealth <= 0)
+ {
+ this.SendEvent(new PlayerDiedEvent());
+ }
+ });
+ }
+}
+
+// Controller - 控制层
+[ContextAware]
+public partial class PlayerController : Node, IController
+{
+ private PlayerModel _playerModel;
+
+ public override void _Ready()
+ {
+ _playerModel = Context.GetModel<PlayerModel>();
+
+ // 监听数据变化,更新视图
+ _playerModel.Health.Register(UpdateHealthUI);
+ _playerModel.Score.Register(UpdateScoreUI);
+ }
+
+ // 处理用户输入
+ public override void _Input(InputEvent @event)
+ {
+ if (@event is InputEventKey keyEvent && keyEvent.Pressed)
+ {
+ if (keyEvent.Keycode == Key.Space)
+ {
+ // 发送命令修改 Model
+ Context.SendCommand(new AttackCommand());
+ }
+ }
+ }
+
+ // 更新视图
+ private void UpdateHealthUI(int health)
+ {
+ var healthBar = GetNode<ProgressBar>("HealthBar");
+ healthBar.Value = health;
+ }
+
+ private void UpdateScoreUI(int score)
+ {
+ var scoreLabel = GetNode<Label>("ScoreLabel");
+ scoreLabel.Text = $"Score: {score}";
+ }
+}
+
+// System - 业务逻辑层(可选)
+public class CombatSystem : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ this.RegisterEvent<AttackCommand>(OnAttack);
+ }
+
+ private void OnAttack(AttackCommand cmd)
+ {
+ var playerModel = this.GetModel<PlayerModel>();
+ var enemyModel = this.GetModel<EnemyModel>();
+
+ // 计算伤害
+ int damage = CalculateDamage(playerModel, enemyModel);
+ enemyModel.Health.Value -= damage;
+
+ // 增加分数
+ if (enemyModel.Health.Value <= 0)
+ {
+ playerModel.Score.Value += 100;
+ }
+ }
+
+ private int CalculateDamage(PlayerModel player, EnemyModel enemy)
+ {
+ return 10; // 简化示例
+ }
+}
+```
+
+### MVC 优势
+
+- ✅ **职责分离**:Model、View、Controller 各司其职
+- ✅ **易于测试**:可以独立测试每个组件
+- ✅ **可维护性高**:修改一个组件不影响其他组件
+- ✅ **支持多视图**:同一个 Model 可以有多个 View
+
+### 最佳实践
+
+1. **Model 只负责数据**:不包含 UI 逻辑
+2. **Controller 协调交互**:不直接操作 UI 细节
+3. **View 只负责显示**:不包含业务逻辑
+4. **使用事件通信**:Model 变化通过事件通知 Controller
+
+## MVVM 模式
+
+### 概念
+
+MVVM(Model-View-ViewModel)是 MVC 的变体,强调数据绑定和响应式编程:
+
+- **Model**:数据和业务逻辑
+- **View**:用户界面
+- **ViewModel**:View 的抽象,提供数据绑定
+
+### 在 GFramework 中的实现
+
+```csharp
+// Model - 数据层
+public class GameModel : AbstractModel
+{
+ public BindableProperty<int> CurrentLevel { get; } = new(1);
+ public BindableProperty<float> Progress { get; } = new(0f);
+ public BindableProperty<bool> IsLoading { get; } = new(false);
+
+ protected override void OnInit()
+ {
+ Progress.Register(progress =>
+ {
+ if (progress >= 1.0f)
+ {
+ this.SendEvent(new LevelCompletedEvent());
+ }
+ });
+ }
+}
+
+// ViewModel - 视图模型(在 GFramework 中,Model 本身就是 ViewModel)
+public class PlayerViewModel : AbstractModel
+{
+ private PlayerModel _playerModel;
+
+ // 计算属性
+ public BindableProperty<string> HealthText { get; } = new("");
+ public BindableProperty<float> HealthPercentage { get; } = new(1.0f);
+ public BindableProperty<bool> IsAlive { get; } = new(true);
+
+ protected override void OnInit()
+ {
+ _playerModel = this.GetModel<PlayerModel>();
+
+ // 绑定数据转换
+ _playerModel.Health.Register(health =>
+ {
+ HealthText.Value = $"{health} / {_playerModel.MaxHealth.Value}";
+ HealthPercentage.Value = (float)health / _playerModel.MaxHealth.Value;
+ IsAlive.Value = health > 0;
+ });
+ }
+}
+
+// View - 视图层
+[ContextAware]
+public partial class PlayerView : Control, IController
+{
+ private PlayerViewModel _viewModel;
+ private Label _healthLabel;
+ private ProgressBar _healthBar;
+ private Panel _deathPanel;
+
+ public override void _Ready()
+ {
+ _viewModel = Context.GetModel<PlayerViewModel>();
+
+ _healthLabel = GetNode<Label>("HealthLabel");
+ _healthBar = GetNode<ProgressBar>("HealthBar");
+ _deathPanel = GetNode<Panel>("DeathPanel");
+
+ // 数据绑定
+ _viewModel.HealthText.Register(text => _healthLabel.Text = text);
+ _viewModel.HealthPercentage.Register(pct => _healthBar.Value = pct * 100);
+ _viewModel.IsAlive.Register(alive => _deathPanel.Visible = !alive);
+ }
+}
+```
+
+### MVVM 优势
+
+- ✅ **自动更新 UI**:数据变化自动反映到界面
+- ✅ **减少样板代码**:不需要手动更新 UI
+- ✅ **易于测试**:ViewModel 可以独立测试
+- ✅ **支持复杂 UI**:适合数据驱动的界面
+
+### 最佳实践
+
+1. **使用 BindableProperty**:实现响应式数据
+2. **ViewModel 不依赖 View**:保持单向依赖
+3. **计算属性放在 ViewModel**:如百分比、格式化文本
+4. **避免在 View 中写业务逻辑**:只负责数据绑定
+
+## 命令模式
+
+### 概念
+
+命令模式将请求封装为对象,从而支持参数化、队列化、日志记录和撤销操作。
+
+### 在 GFramework 中的实现
+
+```csharp
+// 定义命令输入
+public class BuyItemInput : ICommandInput
+{
+ public string ItemId { get; set; }
+ public int Quantity { get; set; }
+}
+
+// 实现命令
+public class BuyItemCommand : AbstractCommand<BuyItemInput>
+{
+ protected override void OnExecute(BuyItemInput input)
+ {
+ var playerModel = this.GetModel<PlayerModel>();
+ var inventoryModel = this.GetModel<InventoryModel>();
+ var shopModel = this.GetModel<ShopModel>();
+
+ // 获取物品信息
+ var item = shopModel.GetItem(input.ItemId);
+ var totalCost = item.Price * input.Quantity;
+
+ // 检查金币
+ if (playerModel.Gold.Value < totalCost)
+ {
+ this.SendEvent(new InsufficientGoldEvent());
+ return;
+ }
+
+ // 扣除金币
+ playerModel.Gold.Value -= totalCost;
+
+ // 添加物品
+ inventoryModel.AddItem(input.ItemId, input.Quantity);
+
+ // 发送事件
+ this.SendEvent(new ItemPurchasedEvent
+ {
+ ItemId = input.ItemId,
+ Quantity = input.Quantity,
+ Cost = totalCost
+ });
+ }
+}
+
+// 使用命令
+[ContextAware]
+public partial class ShopController : IController
+{
+ public void OnBuyButtonClicked(string itemId, int quantity)
+ {
+ // 创建并发送命令
+ var input = new BuyItemInput
+ {
+ ItemId = itemId,
+ Quantity = quantity
+ };
+
+ Context.SendCommand(new BuyItemCommand { Input = input });
+ }
+}
+```
+
+### 支持撤销的命令
+
+```csharp
+public interface IUndoableCommand : ICommand
+{
+ void Undo();
+}
+
+public class MoveCommand : AbstractCommand, IUndoableCommand
+{
+ private Vector2 _previousPosition;
+ private Vector2 _newPosition;
+
+ public MoveCommand(Vector2 newPosition)
+ {
+ _newPosition = newPosition;
+ }
+
+ protected override void OnExecute()
+ {
+ var playerModel = this.GetModel<PlayerModel>();
+ _previousPosition = playerModel.Position.Value;
+ playerModel.Position.Value = _newPosition;
+ }
+
+ public void Undo()
+ {
+ var playerModel = this.GetModel<PlayerModel>();
+ playerModel.Position.Value = _previousPosition;
+ }
+}
+
+// 命令历史管理器
+public class CommandHistory
+{
+ private readonly Stack<IUndoableCommand> _history = new();
+
+ public void Execute(IUndoableCommand command)
+ {
+ command.Execute();
+ _history.Push(command);
+ }
+
+ public void Undo()
+ {
+ if (_history.Count > 0)
+ {
+ var command = _history.Pop();
+ command.Undo();
+ }
+ }
+}
+```
+
+### 命令模式优势
+
+- ✅ **解耦发送者和接收者**:调用者不需要知道实现细节
+- ✅ **支持撤销/重做**:保存命令历史
+- ✅ **支持队列和日志**:可以记录所有操作
+- ✅ **易于扩展**:添加新命令不影响现有代码
+
+### 最佳实践
+
+1. **命令保持原子性**:一个命令完成一个完整操作
+2. **使用输入对象传参**:避免构造函数参数过多
+3. **命令无状态**:执行完即可丢弃
+4. **发送事件通知结果**:而不是返回值
+
+## 查询模式
+
+### 概念
+
+查询模式(CQRS 的一部分)将读操作与写操作分离,查询只读取数据,不修改状态。
+
+### 在 GFramework 中的实现
+
+```csharp
+// 定义查询输入
+public class GetPlayerStatsInput : IQueryInput
+{
+ public string PlayerId { get; set; }
+}
+
+// 定义查询结果
+public class PlayerStats
+{
+ public int Level { get; set; }
+ public int Health { get; set; }
+ public int MaxHealth { get; set; }
+ public int Attack { get; set; }
+ public int Defense { get; set; }
+ public int TotalPower { get; set; }
+}
+
+// 实现查询
+public class GetPlayerStatsQuery : AbstractQuery<GetPlayerStatsInput, PlayerStats>
+{
+ protected override PlayerStats OnDo(GetPlayerStatsInput input)
+ {
+ var playerModel = this.GetModel<PlayerModel>();
+ var equipmentModel = this.GetModel<EquipmentModel>();
+
+ // 计算总战力
+ int basePower = playerModel.Level.Value * 10;
+ int equipmentPower = equipmentModel.GetTotalPower();
+
+ return new PlayerStats
+ {
+ Level = playerModel.Level.Value,
+ Health = playerModel.Health.Value,
+ MaxHealth = playerModel.MaxHealth.Value,
+ Attack = playerModel.Attack.Value + equipmentModel.GetAttackBonus(),
+ Defense = playerModel.Defense.Value + equipmentModel.GetDefenseBonus(),
+ TotalPower = basePower + equipmentPower
+ };
+ }
+}
+
+// 使用查询
+[ContextAware]
+public partial class CharacterPanelController : IController
+{
+ public void ShowCharacterStats()
+ {
+ var input = new GetPlayerStatsInput { PlayerId = "player1" };
+ var query = new GetPlayerStatsQuery { Input = input };
+ var stats = Context.SendQuery(query);
+
+ // 显示统计信息
+ DisplayStats(stats);
+ }
+
+ private void DisplayStats(PlayerStats stats)
+ {
+ Console.WriteLine($"Level: {stats.Level}");
+ Console.WriteLine($"Health: {stats.Health}/{stats.MaxHealth}");
+ Console.WriteLine($"Attack: {stats.Attack}");
+ Console.WriteLine($"Defense: {stats.Defense}");
+ Console.WriteLine($"Total Power: {stats.TotalPower}");
+ }
+}
+```
+
+### 复杂查询示例
+
+```csharp
+// 查询背包中可装备的物品
+public class GetEquippableItemsQuery : AbstractQuery<EmptyQueryInput, List<Item>>
+{
+ protected override List<Item> OnDo(EmptyQueryInput input)
+ {
+ var inventoryModel = this.GetModel<InventoryModel>();
+ var playerModel = this.GetModel<PlayerModel>();
+
+ return inventoryModel.GetAllItems()
+ .Where(item => item.Type == ItemType.Equipment)
+ .Where(item => item.RequiredLevel <= playerModel.Level.Value)
+ .OrderByDescending(item => item.Power)
+ .ToList();
+ }
+}
+
+// 组合查询
+public class CanUseSkillQuery : AbstractQuery<CanUseSkillInput, bool>
+{
+ protected override bool OnDo(CanUseSkillInput input)
+ {
+ var playerModel = this.GetModel<PlayerModel>();
+
+ // 查询技能消耗
+ var costQuery = new GetSkillCostQuery { Input = new GetSkillCostInput { SkillId = input.SkillId } };
+ var cost = this.SendQuery(costQuery);
+
+ // 查询冷却状态
+ var cooldownQuery = new IsSkillOnCooldownQuery { Input = new IsSkillOnCooldownInput { SkillId = input.SkillId } };
+ var onCooldown = this.SendQuery(cooldownQuery);
+
+ // 综合判断
+ return playerModel.Mana.Value >= cost.ManaCost
+ && !onCooldown
+ && playerModel.Health.Value > 0;
+ }
+}
+```
+
+### 查询模式优势
+
+- ✅ **职责分离**:读写操作明确分离
+- ✅ **易于优化**:可以针对查询进行缓存优化
+- ✅ **提高可读性**:查询意图清晰
+- ✅ **支持复杂查询**:可以组合多个简单查询
+
+### 最佳实践
+
+1. **查询只读取,不修改**:保持查询的纯粹性
+2. **使用清晰的命名**:Get、Is、Can、Has 等前缀
+3. **避免过度查询**:频繁查询考虑使用 BindableProperty
+4. **合理使用缓存**:复杂计算结果可以缓存
+
+## 事件驱动模式
+
+### 概念
+
+事件驱动模式通过事件实现组件间的松耦合通信。发送者不需要知道接收者,接收者通过订阅事件来响应变化。
+
+### 在 GFramework 中的实现
+
+```csharp
+// 定义事件
+public struct PlayerDiedEvent
+{
+ public Vector3 Position { get; set; }
+ public string Cause { get; set; }
+ public int FinalScore { get; set; }
+}
+
+public struct EnemyKilledEvent
+{
+ public string EnemyId { get; set; }
+ public int Reward { get; set; }
+}
+
+// Model 发送事件
+public class PlayerModel : AbstractModel
+{
+ public BindableProperty<int> Health { get; } = new(100);
+ public BindableProperty<Vector3> Position { get; } = new(Vector3.Zero);
+
+ protected override void OnInit()
+ {
+ Health.Register(newHealth =>
+ {
+ if (newHealth <= 0)
+ {
+ // 发送玩家死亡事件
+ this.SendEvent(new PlayerDiedEvent
+ {
+ Position = Position.Value,
+ Cause = "Health depleted",
+ FinalScore = this.GetModel<GameModel>().Score.Value
+ });
+ }
+ });
+ }
+}
+
+// System 监听和发送事件
+public class AchievementSystem : AbstractSystem
+{
+ private int _enemyKillCount = 0;
+
+ protected override void OnInit()
+ {
+ // 监听敌人被杀事件
+ this.RegisterEvent<EnemyKilledEvent>(OnEnemyKilled);
+
+ // 监听玩家死亡事件
+ this.RegisterEvent<PlayerDiedEvent>(OnPlayerDied);
+ }
+
+ private void OnEnemyKilled(EnemyKilledEvent e)
+ {
+ _enemyKillCount++;
+
+ // 检查成就条件
+ if (_enemyKillCount == 10)
+ {
+ this.SendEvent(new AchievementUnlockedEvent
+ {
+ AchievementId = "first_blood_10",
+ Title = "新手猎人",
+ Description = "击败10个敌人"
+ });
+ }
+ }
+
+ private void OnPlayerDied(PlayerDiedEvent e)
+ {
+ // 记录统计数据
+ var statsModel = this.GetModel<StatisticsModel>();
+ statsModel.RecordDeath(e.Position, e.Cause);
+ }
+}
+
+// Controller 监听事件
+[ContextAware]
+public partial class UIController : IController
+{
+ private IUnRegisterList _unregisterList = new UnRegisterList();
+
+ public void Initialize()
+ {
+ // 监听成就解锁事件
+ Context.RegisterEvent(OnAchievementUnlocked)
+ .AddToUnregisterList(_unregisterList);
+
+ // 监听玩家死亡事件
+ Context.RegisterEvent(OnPlayerDied)
+ .AddToUnregisterList(_unregisterList);
+ }
+
+ private void OnAchievementUnlocked(AchievementUnlockedEvent e)
+ {
+ ShowAchievementNotification(e.Title, e.Description);
+ }
+
+ private void OnPlayerDied(PlayerDiedEvent e)
+ {
+ ShowGameOverScreen(e.FinalScore);
+ }
+
+ public void Cleanup()
+ {
+ _unregisterList.UnRegisterAll();
+ }
+}
+```
+
+### 事件组合
+
+```csharp
+using GFramework.SourceGenerators.Abstractions.rule;
+
+// 使用 OrEvent 组合多个事件
+[ContextAware]
+public partial class InputController : IController
+{
+ public void Initialize()
+ {
+ var onAnyInput = new OrEvent()
+ .Or(keyboardEvent)
+ .Or(mouseEvent)
+ .Or(gamepadEvent);
+
+ onAnyInput.Register(() =>
+ {
+ ResetIdleTimer();
+ });
+ }
+}
+```
+
+### 事件驱动模式优势
+
+- ✅ **松耦合**:发送者和接收者互不依赖
+- ✅ **一对多通信**:一个事件可以有多个监听者
+- ✅ **易于扩展**:添加新监听者不影响现有代码
+- ✅ **支持异步**:事件可以异步处理
+
+### 最佳实践
+
+1. **事件命名使用过去式**:PlayerDiedEvent、LevelCompletedEvent
+2. **事件使用结构体**:减少内存分配
+3. **及时注销事件**:使用 IUnRegisterList 管理
+4. **避免事件循环**:事件处理器中谨慎发送新事件
+
+## 依赖注入模式
+
+### 概念
+
+依赖注入(DI)是一种实现控制反转(IoC)的技术,通过外部注入依赖而不是在类内部创建。
+
+### 在 GFramework 中的实现
+
+```csharp
+// 定义接口
+public interface IStorageService
+{
+ Task SaveAsync<T>(string key, T data);
+ Task<T> LoadAsync<T>(string key);
+}
+
+public interface IAudioService
+{
+ void PlaySound(string soundId);
+ void PlayMusic(string musicId);
+}
+
+// 实现服务
+public class LocalStorageService : IStorageService
+{
+ public async Task SaveAsync<T>(string key, T data)
+ {
+ var json = JsonSerializer.Serialize(data);
+ await File.WriteAllTextAsync($"saves/{key}.json", json);
+ }
+
+ public async Task<T> LoadAsync<T>(string key)
+ {
+ var json = await File.ReadAllTextAsync($"saves/{key}.json");
+ return JsonSerializer.Deserialize<T>(json);
+ }
+}
+
+public class GodotAudioService : IAudioService
+{
+ private AudioStreamPlayer _soundPlayer;
+ private AudioStreamPlayer _musicPlayer;
+
+ public void PlaySound(string soundId)
+ {
+ var sound = GD.Load<AudioStream>($"res://sounds/{soundId}.ogg");
+ _soundPlayer.Stream = sound;
+ _soundPlayer.Play();
+ }
+
+ public void PlayMusic(string musicId)
+ {
+ var music = GD.Load<AudioStream>($"res://music/{musicId}.ogg");
+ _musicPlayer.Stream = music;
+ _musicPlayer.Play();
+ }
+}
+
+// 在架构中注册服务
+public class GameArchitecture : Architecture
+{
+ protected override void Init()
+ {
+ // 注册服务实现
+ RegisterUtility<IStorageService>(new LocalStorageService());
+ RegisterUtility<IAudioService>(new GodotAudioService());
+
+ // 注册 System(System 会自动获取依赖)
+ RegisterSystem(new SaveSystem());
+ RegisterSystem(new AudioSystem());
+ }
+}
+
+// System 使用依赖注入
+public class SaveSystem : AbstractSystem
+{
+ private IStorageService _storageService;
+
+ protected override void OnInit()
+ {
+ // 从容器获取依赖
+ _storageService = this.GetUtility<IStorageService>();
+
+ this.RegisterEvent<SaveGameEvent>(OnSaveGame);
+ }
+
+ private async void OnSaveGame(SaveGameEvent e)
+ {
+ var playerModel = this.GetModel<PlayerModel>();
+ var saveData = new SaveData
+ {
+ PlayerName = playerModel.Name.Value,
+ Level = playerModel.Level.Value,
+ Health = playerModel.Health.Value
+ };
+
+ await _storageService.SaveAsync("current_save", saveData);
+ }
+}
+```
+
+### 构造函数注入(推荐)
+
+```csharp
+public class SaveSystem : AbstractSystem
+{
+ private readonly IStorageService _storageService;
+ private readonly IAudioService _audioService;
+
+ // 通过构造函数注入依赖
+ public SaveSystem(IStorageService storageService, IAudioService audioService)
+ {
+ _storageService = storageService;
+ _audioService = audioService;
+ }
+
+ protected override void OnInit()
+ {
+ this.RegisterEvent<SaveGameEvent>(OnSaveGame);
+ }
+
+ private async void OnSaveGame(SaveGameEvent e)
+ {
+ await _storageService.SaveAsync("save", e.Data);
+ _audioService.PlaySound("save_success");
+ }
+}
+
+// 注册时传入依赖
+public class GameArchitecture : Architecture
+{
+ protected override void Init()
+ {
+ var storageService = new LocalStorageService();
+ var audioService = new GodotAudioService();
+
+ RegisterUtility<IStorageService>(storageService);
+ RegisterUtility<IAudioService>(audioService);
+
+ // 构造函数注入
+ RegisterSystem(new SaveSystem(storageService, audioService));
+ }
+}
+```
+
+### 依赖注入优势
+
+- ✅ **易于测试**:可以注入模拟对象
+- ✅ **松耦合**:依赖接口而非实现
+- ✅ **灵活配置**:运行时选择实现
+- ✅ **提高可维护性**:依赖关系清晰
+
+### 最佳实践
+
+1. **依赖接口而非实现**:使用 IStorageService 而非 LocalStorageService
+2. **优先使用构造函数注入**:依赖关系更明确
+3. **避免循环依赖**:System 不应相互依赖
+4. **使用 IoC 容器管理生命周期**:让框架管理对象创建
+
+## 服务定位器模式
+
+### 概念
+
+服务定位器模式提供一个全局访问点来获取服务,是依赖注入的替代方案。
+
+### 在 GFramework 中的实现
+
+```csharp
+// GFramework 的 Architecture 本身就是服务定位器
+public class GameplaySystem : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ // 通过服务定位器获取服务
+ var playerModel = this.GetModel<PlayerModel>();
+ var audioSystem = this.GetSystem<AudioSystem>();
+ var storageUtility = this.GetUtility<IStorageUtility>();
+
+ // 使用服务
+ playerModel.Health.Value = 100;
+ audioSystem.PlayBGM("gameplay");
+ }
+}
+
+// 在 Controller 中使用
+[ContextAware]
+public partial class MenuController : IController
+{
+ public void OnStartButtonClicked()
+ {
+ // 通过架构获取服务
+ var gameModel = Context.GetModel();
+ gameModel.GameState.Value = GameState.Playing;
+
+ // 发送命令
+ Context.SendCommand(new StartGameCommand());
+ }
+}
+```
+
+### 自定义服务定位器
+
+```csharp
+// 创建专门的服务定位器
+public static class ServiceLocator
+{
+ private static readonly Dictionary<Type, object> _services = new();
+
+ public static void Register<T>(T service)
+ {
+ _services[typeof(T)] = service;
+ }
+
+ public static T Get<T>()
+ {
+ if (_services.TryGetValue(typeof(T), out var service))
+ {
+ return (T)service;
+ }
+ throw new InvalidOperationException($"Service {typeof(T)} not registered");
+ }
+
+ public static void Clear()
+ {
+ _services.Clear();
+ }
+}
+
+// 使用自定义服务定位器
+public class GameInitializer
+{
+ public void Initialize()
+ {
+ // 注册服务
+ ServiceLocator.Register<IAnalyticsService>(new AnalyticsService());
+ ServiceLocator.Register<ILeaderboardService>(new LeaderboardService());
+ }
+}
+
+public class GameOverScreen
+{
+ public void SubmitScore(int score)
+ {
+ // 获取服务
+ var leaderboard = ServiceLocator.Get<ILeaderboardService>();
+ leaderboard.SubmitScore(score);
+
+ var analytics = ServiceLocator.Get<IAnalyticsService>();
+ analytics.TrackEvent("game_over", new { score });
+ }
+}
+```
+
+### 服务定位器 vs 依赖注入
+
+| 特性 | 服务定位器 | 依赖注入 |
+|-----------|--------------|------------|
+| **依赖可见性** | 隐式(运行时获取) | 显式(构造函数参数) |
+| **易用性** | 简单直接 | 需要配置 |
+| **测试性** | 较难(需要模拟全局状态) | 容易(注入模拟对象) |
+| **编译时检查** | 无 | 有 |
+| **适用场景** | 快速原型、小项目 | 大型项目、团队协作 |
+
+### 最佳实践
+
+1. **小项目使用服务定位器**:简单直接
+2. **大项目使用依赖注入**:更易维护
+3. **避免过度使用**:不要把所有东西都放入定位器
+4. **提供清晰的 API**:GetModel、GetSystem、GetUtility
+
+## 对象池模式
+
+### 概念
+
+对象池模式通过复用对象来减少内存分配和垃圾回收,提高性能。
+
+### 在 GFramework 中的实现
+
+```csharp
+// 定义可池化对象
+public class Bullet : Node2D, IPoolableNode
+{
+ public bool IsInPool { get; set; }
+
+ public void OnSpawn()
+ {
+ // 从池中取出时调用
+ Visible = true;
+ IsInPool = false;
+ }
+
+ public void OnRecycle()
+ {
+ // 回收到池中时调用
+ Visible = false;
+ IsInPool = true;
+ Position = Vector2.Zero;
+ Rotation = 0;
+ }
+}
+
+// 创建对象池系统
+public class BulletPoolSystem : AbstractNodePoolSystem<Bullet>
+{
+ protected override Bullet CreateInstance()
+ {
+ var bullet = new Bullet();
+ // 初始化子弹
+ return bullet;
+ }
+
+ protected override void OnInit()
+ {
+ // 预创建对象
+ PrewarmPool(50);
+ }
+}
+
+// 使用对象池
+public class WeaponSystem : AbstractSystem
+{
+ private BulletPoolSystem _bulletPool;
+
+ protected override void OnInit()
+ {
+ _bulletPool = this.GetSystem<BulletPoolSystem>();
+ this.RegisterEvent<FireWeaponEvent>(OnFireWeapon);
+ }
+
+ private void OnFireWeapon(FireWeaponEvent e)
+ {
+ // 从池中获取子弹
+ var bullet = _bulletPool.Spawn();
+ bullet.Position = e.Position;
+ bullet.Rotation = e.Direction;
+
+ // 3秒后回收
+ ScheduleRecycle(bullet, 3.0f);
+ }
+
+ private async void ScheduleRecycle(Bullet bullet, float delay)
+ {
+ await Task.Delay((int)(delay * 1000));
+ _bulletPool.Recycle(bullet);
+ }
+}
+```
+
+### 通用对象池
+
+```csharp
+// 通用对象池实现
+public class ObjectPool<T> where T : class, new()
+{
+ private readonly Stack<T> _pool = new();
+ private readonly Action<T> _onSpawn;
+ private readonly Action<T> _onRecycle;
+ private readonly int _maxSize;
+
+ public ObjectPool(int initialSize = 10, int maxSize = 100,
+ Action<T> onSpawn = null, Action<T> onRecycle = null)
+ {
+ _maxSize = maxSize;
+ _onSpawn = onSpawn;
+ _onRecycle = onRecycle;
+
+ // 预创建对象
+ for (int i = 0; i < initialSize; i++)
+ {
+ _pool.Push(new T());
+ }
+ }
+
+ public T Spawn()
+ {
+ T obj = _pool.Count > 0 ? _pool.Pop() : new T();
+ _onSpawn?.Invoke(obj);
+ return obj;
+ }
+
+ public void Recycle(T obj)
+ {
+ if (_pool.Count < _maxSize)
+ {
+ _onRecycle?.Invoke(obj);
+ _pool.Push(obj);
+ }
+ }
+
+ public void Clear()
+ {
+ _pool.Clear();
+ }
+}
+
+// 使用通用对象池
+public class ParticleSystem : AbstractSystem
+{
+ private ObjectPool<Particle> _particlePool;
+
+ protected override void OnInit()
+ {
+ _particlePool = new ObjectPool<Particle>(
+ initialSize: 100,
+ maxSize: 500,
+ onSpawn: p => p.Reset(),
+ onRecycle: p => p.Clear()
+ );
+ }
+
+ public void EmitParticles(Vector3 position, int count)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ var particle = _particlePool.Spawn();
+ particle.Position = position;
+ particle.Velocity = GetRandomVelocity();
+ }
+ }
+}
+```
+
+### 对象池优势
+
+- ✅ **减少 GC 压力**:复用对象,减少内存分配
+- ✅ **提高性能**:避免频繁创建销毁对象
+- ✅ **稳定帧率**:减少 GC 导致的卡顿
+- ✅ **适合高频对象**:子弹、粒子、特效等
+
+### 最佳实践
+
+1. **预热池**:提前创建对象避免运行时分配
+2. **设置最大容量**:防止池无限增长
+3. **重置对象状态**:OnRecycle 中清理状态
+4. **监控池使用情况**:记录 Spawn/Recycle 次数
+
+## 状态模式
+
+### 概念
+
+状态模式允许对象在内部状态改变时改变其行为,将状态相关的行为封装到独立的状态类中。
+
+### 在 GFramework 中的实现
+
+```csharp
+// 定义游戏状态
+public class MenuState : ContextAwareStateBase
+{
+ public override void OnEnter(IState from)
+ {
+ Console.WriteLine("进入菜单状态");
+
+ // 显示菜单 UI
+ var uiSystem = this.GetSystem<UISystem>();
+ uiSystem.ShowMenu();
+
+ // 播放菜单音乐
+ var audioSystem = this.GetSystem<AudioSystem>();
+ audioSystem.PlayBGM("menu_theme");
+ }
+
+ public override void OnExit(IState to)
+ {
+ Console.WriteLine("退出菜单状态");
+
+ // 隐藏菜单 UI
+ var uiSystem = this.GetSystem<UISystem>();
+ uiSystem.HideMenu();
+ }
+
+ public override bool CanTransitionTo(IState target)
+ {
+ // 菜单可以转换到游戏或设置状态
+ return target is GameplayState or SettingsState;
+ }
+}
+
+public class GameplayState : ContextAwareStateBase
+{
+ public override void OnEnter(IState from)
+ {
+ Console.WriteLine("进入游戏状态");
+
+ // 初始化游戏
+ var gameModel = this.GetModel<GameModel>();
+ gameModel.Reset();
+
+ // 加载关卡
+ this.SendCommand(new LoadLevelCommand { LevelId = 1 });
+
+ // 播放游戏音乐
+ var audioSystem = this.GetSystem<AudioSystem>();
+ audioSystem.PlayBGM("gameplay_theme");
+ }
+
+ public override void OnExit(IState to)
+ {
+ Console.WriteLine("退出游戏状态");
+
+ // 保存游戏进度
+ this.SendCommand(new SaveGameCommand());
+ }
+
+ public override bool CanTransitionTo(IState target)
+ {
+ // 游戏中可以暂停或结束
+ return target is PauseState or GameOverState;
+ }
+}
+
+public class PauseState : ContextAwareStateBase
+{
+ public override void OnEnter(IState from)
+ {
+ Console.WriteLine("进入暂停状态");
+
+ // 暂停游戏
+ var timeSystem = this.GetSystem<TimeSystem>();
+ timeSystem.Pause();
+
+ // 显示暂停菜单
+ var uiSystem = this.GetSystem<UISystem>();
+ uiSystem.ShowPauseMenu();
+ }
+
+ public override void OnExit(IState to)
+ {
+ Console.WriteLine("退出暂停状态");
+
+ // 恢复游戏
+ var timeSystem = this.GetSystem<TimeSystem>();
+ timeSystem.Resume();
+
+ // 隐藏暂停菜单
+ var uiSystem = this.GetSystem<UISystem>();
+ uiSystem.HidePauseMenu();
+ }
+
+ public override bool CanTransitionTo(IState target)
+ {
+ // 暂停只能返回游戏或退出到菜单
+ return target is GameplayState or MenuState;
+ }
+}
+
+// 注册状态机
+public class GameArchitecture : Architecture
+{
+ protected override void Init()
+ {
+ // 创建状态机系统
+ var stateMachine = new StateMachineSystem();
+
+ // 注册所有状态
+ stateMachine
+ .Register(new MenuState())
+ .Register(new GameplayState())
+ .Register(new PauseState())
+ .Register(new GameOverState())
+ .Register(new SettingsState());
+
+ RegisterSystem<IStateMachineSystem>(stateMachine);
+ }
+}
+
+// 使用状态机
+[ContextAware]
+public partial class GameController : IController
+{
+ public async Task StartGame()
+ {
+ var stateMachine = Context.GetSystem();
+ await stateMachine.ChangeToAsync();
+ }
+
+ public async Task PauseGame()
+ {
+ var stateMachine = Context.GetSystem();
+ await stateMachine.ChangeToAsync();
+ }
+
+ public async Task ResumeGame()
+ {
+ var stateMachine = Context.GetSystem();
+ await stateMachine.ChangeToAsync();
+ }
+}
+```
+
+### 异步状态
+
+```csharp
+public class LoadingState : AsyncContextAwareStateBase
+{
+ public override async Task OnEnterAsync(IState from)
+ {
+ Console.WriteLine("开始加载...");
+
+ // 显示加载界面
+ var uiSystem = this.GetSystem<UISystem>();
+ uiSystem.ShowLoadingScreen();
+
+ // 异步加载资源
+ await LoadResourcesAsync();
+
+ Console.WriteLine("加载完成");
+
+ // 自动切换到游戏状态
+ var stateMachine = this.GetSystem<IStateMachineSystem>();
+ await stateMachine.ChangeToAsync<GameplayState>();
+ }
+
+ private async Task LoadResourcesAsync()
+ {
+ // 模拟异步加载
+ await Task.Delay(2000);
+ }
+
+ public override async Task OnExitAsync(IState to)
+ {
+ // 隐藏加载界面
+ var uiSystem = this.GetSystem<UISystem>();
+ uiSystem.HideLoadingScreen();
+
+ await Task.CompletedTask;
+ }
+}
+```
+
+### 状态模式优势
+
+- ✅ **清晰的状态管理**:每个状态独立封装
+- ✅ **易于扩展**:添加新状态不影响现有代码
+- ✅ **状态转换验证**:CanTransitionTo 控制合法转换
+- ✅ **支持异步操作**:异步状态处理加载等操作
+
+### 最佳实践
+
+1. **状态保持单一职责**:每个状态只负责一个场景
+2. **使用转换验证**:防止非法状态转换
+3. **在 OnEnter 初始化,OnExit 清理**:保持状态独立
+4. **异步操作使用异步状态**:避免阻塞主线程
+
+## 设计原则
+
+### 1. 单一职责原则 (SRP)
+
+确保每个类只负责一个功能领域:
+
+```csharp
+// ✅ 好的做法:职责单一
+public class PlayerMovementController : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ this.RegisterEvent(OnPlayerInput);
+ }
+
+ private void OnPlayerInput(PlayerInputEvent e)
+ {
+ // 只负责移动逻辑
+ ProcessMovement(e.Direction);
+ }
+
+ private void ProcessMovement(Vector2 direction)
+ {
+ // 移动相关的业务逻辑
+ }
+}
+
+public class PlayerCombatController : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ this.RegisterEvent(OnAttackInput);
+ }
+
+ private void OnAttackInput(AttackInputEvent e)
+ {
+ // 只负责战斗逻辑
+ ProcessAttack(e.Target);
+ }
+
+ private void ProcessAttack(Entity target)
+ {
+ // 战斗相关的业务逻辑
+ }
+}
+
+// ❌ 避免:职责混乱
+public class PlayerController : AbstractSystem
+{
+ private void OnPlayerInput(PlayerInputEvent e)
+ {
+ // 移动逻辑
+ ProcessMovement(e.Direction);
+
+ // 战斗逻辑
+ if (e.IsAttacking)
+ {
+ ProcessAttack(e.Target);
+ }
+
+ // UI逻辑
+ UpdateHealthBar();
+
+ // 音效逻辑
+ PlaySoundEffect();
+
+ // 存档逻辑
+ SaveGame();
+
+ // 职责太多,难以维护
+ }
+}
+```
+
+### 2. 开闭原则 (OCP)
+
+设计应该对扩展开放,对修改封闭:
+
+```csharp
+// ✅ 好的做法:使用接口和策略模式
+public interface IWeaponStrategy
+{
+ void Attack(Entity attacker, Entity target);
+ int CalculateDamage(Entity attacker, Entity target);
+}
+
+public class SwordWeaponStrategy : IWeaponStrategy
+{
+ public void Attack(Entity attacker, Entity target)
+ {
+ var damage = CalculateDamage(attacker, target);
+ target.TakeDamage(damage);
+ PlaySwingAnimation();
+ }
+
+ public int CalculateDamage(Entity attacker, Entity target)
+ {
+ return attacker.Strength + GetSwordBonus() - target.Armor;
+ }
+}
+
+public class MagicWeaponStrategy : IWeaponStrategy
+{
+ public void Attack(Entity attacker, Entity target)
+ {
+ var damage = CalculateDamage(attacker, target);
+ target.TakeDamage(damage);
+ CastMagicEffect();
+ }
+
+ public int CalculateDamage(Entity attacker, Entity target)
+ {
+ return attacker.Intelligence * 2 + GetMagicBonus() - target.MagicResistance;
+ }
+}
+
+public class CombatSystem : AbstractSystem
+{
+ private readonly Dictionary _weaponStrategies;
+
+ public CombatSystem()
+ {
+ _weaponStrategies = new()
+ {
+ { WeaponType.Sword, new SwordWeaponStrategy() },
+ { WeaponType.Magic, new MagicWeaponStrategy() }
+ };
+ }
+
+ public void Attack(Entity attacker, Entity target)
+ {
+ var weaponType = attacker.EquippedWeapon.Type;
+
+ if (_weaponStrategies.TryGetValue(weaponType, out var strategy))
+ {
+ strategy.Attack(attacker, target);
+ }
+ }
+
+ // 添加新武器类型时,只需要添加新的策略,不需要修改现有代码
+ public void RegisterWeaponStrategy(WeaponType type, IWeaponStrategy strategy)
+ {
+ _weaponStrategies[type] = strategy;
+ }
+}
+
+// ❌ 避免:需要修改现有代码来扩展
+public class CombatSystem : AbstractSystem
+{
+ public void Attack(Entity attacker, Entity target)
+ {
+ var weaponType = attacker.EquippedWeapon.Type;
+
+ switch (weaponType)
+ {
+ case WeaponType.Sword:
+ // 剑的攻击逻辑
+ break;
+ case WeaponType.Bow:
+ // 弓的攻击逻辑
+ break;
+ default:
+ throw new NotSupportedException($"Weapon type {weaponType} not supported");
+ }
+
+ // 添加新武器类型时需要修改这里的 switch 语句
+ }
+}
+```
+
+### 3. 依赖倒置原则 (DIP)
+
+高层模块不应该依赖低层模块,两者都应该依赖抽象:
+
+```csharp
+// ✅ 好的做法:依赖抽象
+public interface IDataStorage
+{
+ Task SaveAsync<T>(string key, T data);
+ Task<T> LoadAsync<T>(string key, T defaultValue = default);
+ Task ExistsAsync(string key);
+}
+
+public class FileStorage : IDataStorage
+{
+ public async Task SaveAsync<T>(string key, T data)
+ {
+ var json = JsonConvert.SerializeObject(data);
+ await File.WriteAllTextAsync(GetFilePath(key), json);
+ }
+
+ public async Task<T> LoadAsync<T>(string key, T defaultValue = default)
+ {
+ var filePath = GetFilePath(key);
+ if (!File.Exists(filePath))
+ return defaultValue;
+
+ var json = await File.ReadAllTextAsync(filePath);
+ return JsonConvert.DeserializeObject<T>(json);
+ }
+
+ public async Task ExistsAsync(string key)
+ {
+ return File.Exists(GetFilePath(key));
+ }
+
+ private string GetFilePath(string key)
+ {
+ return $"saves/{key}.json";
+ }
+}
+
+public class CloudStorage : IDataStorage
+{
+ public async Task SaveAsync<T>(string key, T data)
+ {
+ // 云存储实现
+ await UploadToCloud(key, data);
+ }
+
+ public async Task<T> LoadAsync<T>(string key, T defaultValue = default)
+ {
+ // 云存储实现
+ return await DownloadFromCloud<T>(key, defaultValue);
+ }
+
+ public async Task ExistsAsync(string key)
+ {
+ // 云存储实现
+ return await CheckCloudExists(key);
+ }
+}
+
+// 高层模块依赖抽象
+public class SaveSystem : AbstractSystem
+{
+ private readonly IDataStorage _storage;
+
+ public SaveSystem(IDataStorage storage)
+ {
+ _storage = storage;
+ }
+
+ public async Task SaveGameAsync(SaveData data)
+ {
+ await _storage.SaveAsync("current_save", data);
+ }
+
+ public async Task LoadGameAsync()
+ {
+ return await _storage.LoadAsync("current_save");
+ }
+}
+
+// ❌ 避免:依赖具体实现
+public class SaveSystem : AbstractSystem
+{
+ private readonly FileStorage _storage; // 直接依赖具体实现
+
+ public SaveSystem()
+ {
+ _storage = new FileStorage(); // 硬编码依赖
+ }
+
+ // 无法轻松切换到其他存储方式
+}
+```
+
+## 架构分层
+
+### 1. 清晰的层次结构
+
+```csharp
+// ✅ 好的做法:清晰的分层架构
+namespace Game.Models
+{
+ // 数据层:只负责存储状态
+ public class PlayerModel : AbstractModel
+ {
+ public BindableProperty Health { get; } = new(100);
+ public BindableProperty MaxHealth { get; } = new(100);
+ public BindableProperty Position { get; } = new(Vector2.Zero);
+ public BindableProperty State { get; } = new(PlayerState.Idle);
+
+ protected override void OnInit()
+ {
+ // 只处理数据相关的逻辑
+ Health.Register(OnHealthChanged);
+ }
+
+ private void OnHealthChanged(int newHealth)
+ {
+ if (newHealth <= 0)
+ {
+ State.Value = PlayerState.Dead;
+ SendEvent(new PlayerDeathEvent());
+ }
+ }
+ }
+
+ public enum PlayerState
+ {
+ Idle,
+ Moving,
+ Attacking,
+ Dead
+ }
+}
+
+namespace Game.Systems
+{
+ // 业务逻辑层:处理游戏逻辑
+ public class PlayerMovementSystem : AbstractSystem
+ {
+ private PlayerModel _playerModel;
+ private GameModel _gameModel;
+
+ protected override void OnInit()
+ {
+ _playerModel = GetModel();
+ _gameModel = GetModel();
+
+ this.RegisterEvent(OnPlayerInput);
+ }
+
+ private void OnPlayerInput(PlayerInputEvent e)
+ {
+ if (_gameModel.State.Value != GameState.Playing)
+ return;
+
+ if (_playerModel.State.Value == PlayerState.Dead)
+ return;
+
+ // 处理移动逻辑
+ ProcessMovement(e.Direction);
+ }
+
+ private void ProcessMovement(Vector2 direction)
+ {
+ if (direction != Vector2.Zero)
+ {
+ _playerModel.Position.Value += direction.Normalized() * GetMovementSpeed();
+ _playerModel.State.Value = PlayerState.Moving;
+
+ SendEvent(new PlayerMovedEvent {
+ NewPosition = _playerModel.Position.Value,
+ Direction = direction
+ });
+ }
+ else
+ {
+ _playerModel.State.Value = PlayerState.Idle;
+ }
+ }
+
+ private float GetMovementSpeed()
+ {
+ // 从玩家属性或其他地方获取速度
+ return 5.0f;
+ }
+ }
+}
+
+namespace Game.Controllers
+{
+ // 控制层:连接用户输入和业务逻辑
+ [ContextAware]
+ public partial class PlayerController : Node, IController
+ {
+ private PlayerModel _playerModel;
+
+ public override void _Ready()
+ {
+ _playerModel = Context.GetModel();
+
+ // 监听用户输入
+ SetProcessInput(true);
+
+ // 监听数据变化,更新UI
+ _playerModel.Health.Register(UpdateHealthUI);
+ _playerModel.Position.Register(UpdatePosition);
+ }
+
+ public override void _Input(InputEvent @event)
+ {
+ if (@event is InputEventKey keyEvent && keyEvent.Pressed)
+ {
+ var direction = GetInputDirection(keyEvent);
+ Context.SendEvent(new PlayerInputEvent { Direction = direction });
+ }
+ }
+
+ private void UpdateHealthUI(int health)
+ {
+ // 更新UI显示
+ var healthBar = GetNode("UI/HealthBar");
+ healthBar.Value = (float)health / _playerModel.MaxHealth.Value * 100;
+ }
+
+ private void UpdatePosition(Vector2 position)
+ {
+ // 更新玩家位置
+ Position = position;
+ }
+
+ private Vector2 GetInputDirection(InputEventKey keyEvent)
+ {
+ return keyEvent.Keycode switch
+ {
+ Key.W => Vector2.Up,
+ Key.S => Vector2.Down,
+ Key.A => Vector2.Left,
+ Key.D => Vector2.Right,
+ _ => Vector2.Zero
+ };
+ }
+ }
+}
+```
+
+### 2. 避免层次混乱
+
+```csharp
+// ❌ 避免:层次混乱
+public class PlayerController : Node, IController
+{
+ // 混合了数据层、业务逻辑层和控制层的职责
+ public BindableProperty Health { get; } = new(100); // 数据层职责
+
+ public override void _Input(InputEvent @event) // 控制层职责
+ {
+ if (@event is InputEventKey keyEvent && keyEvent.Pressed)
+ {
+ if (keyEvent.Keycode == Key.W)
+ {
+ Position += Vector2.Up * MovementSpeed; // 业务逻辑层职责
+ }
+
+ if (keyEvent.Keycode == Key.Space)
+ {
+ Health -= 10; // 业务逻辑层职责
+ PlaySoundEffect(); // 业务逻辑层职责
+ }
+ }
+ }
+
+ // 这样会导致代码难以测试和维护
+}
+```
+
+## 依赖管理
+
+### 1. 构造函数注入
+
+```csharp
+// ✅ 好的做法:构造函数注入
+public class PlayerCombatSystem : AbstractSystem
+{
+ private readonly PlayerModel _playerModel;
+ private readonly IWeaponService _weaponService;
+ private readonly ISoundService _soundService;
+ private readonly IEffectService _effectService;
+
+ // 通过构造函数注入依赖
+ public PlayerCombatSystem(
+ PlayerModel playerModel,
+ IWeaponService weaponService,
+ ISoundService soundService,
+ IEffectService effectService)
+ {
+ _playerModel = playerModel;
+ _weaponService = weaponService;
+ _soundService = soundService;
+ _effectService = effectService;
+ }
+
+ protected override void OnInit()
+ {
+ this.RegisterEvent(OnAttack);
+ }
+
+ private void OnAttack(AttackEvent e)
+ {
+ var weapon = _weaponService.GetEquippedWeapon(_playerModel);
+ var damage = _weaponService.CalculateDamage(weapon, e.Target);
+
+ e.Target.TakeDamage(damage);
+ _soundService.PlayAttackSound(weapon.Type);
+ _effectService.PlayAttackEffect(_playerModel.Position, weapon.Type);
+ }
+}
+
+// ❌ 避免:依赖注入容器
+public class PlayerCombatSystem : AbstractSystem
+{
+ private PlayerModel _playerModel;
+ private IWeaponService _weaponService;
+ private ISoundService _soundService;
+ private IEffectService _effectService;
+
+ protected override void OnInit()
+ {
+ // 在运行时获取依赖,难以测试
+ _playerModel = GetModel();
+ _weaponService = GetService();
+ _soundService = GetService();
+ _effectService = GetService();
+ }
+
+ // 测试时难以模拟依赖
+}
+```
+
+### 2. 接口隔离
+
+```csharp
+// ✅ 好的做法:小而专注的接口
+public interface IMovementController
+{
+ void Move(Vector2 direction);
+ void Stop();
+ bool CanMove();
+}
+
+public interface ICombatController
+{
+ void Attack(Entity target);
+ void Defend();
+ bool CanAttack();
+}
+
+public interface IUIController
+{
+ void ShowHealthBar();
+ void HideHealthBar();
+ void UpdateHealthDisplay(int currentHealth, int maxHealth);
+}
+
+public class PlayerController : Node, IMovementController, ICombatController, IUIController
+{
+ // 实现各个接口,职责清晰
+}
+
+// ❌ 避免:大而全的接口
+public interface IPlayerController
+{
+ void Move(Vector2 direction);
+ void Stop();
+ void Attack(Entity target);
+ void Defend();
+ void ShowHealthBar();
+ void HideHealthBar();
+ void UpdateHealthDisplay(int currentHealth, int maxHealth);
+ void SaveGame();
+ void LoadGame();
+ void Respawn();
+ void PlayAnimation(string animationName);
+ void StopAnimation();
+ // ... 更多方法,接口过于庞大
+}
+```
+
+## 事件系统设计
+
+### 1. 事件命名和结构
+
+```csharp
+// ✅ 好的做法:清晰的事件命名和结构
+public struct PlayerHealthChangedEvent
+{
+ public int PreviousHealth { get; }
+ public int NewHealth { get; }
+ public int MaxHealth { get; }
+ public Vector3 DamagePosition { get; }
+ public DamageType DamageType { get; }
+}
+
+public struct PlayerDiedEvent
+{
+ public Vector3 DeathPosition { get; }
+ public string CauseOfDeath { get; }
+ public TimeSpan SurvivalTime { get; }
+}
+
+public struct WeaponEquippedEvent
+{
+ public string PlayerId { get; }
+ public WeaponType WeaponType { get; }
+ public string WeaponId { get; }
+}
+
+// ❌ 避免:模糊的事件命名和结构
+public struct PlayerEvent
+{
+ public EventType Type { get; }
+ public object Data { get; } // 类型不安全
+ public Dictionary Properties { get; } // 难以理解
+}
+```
+
+### 2. 事件处理职责
+
+```csharp
+// ✅ 好的做法:单一职责的事件处理
+public class UIHealthBarController : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ this.RegisterEvent(OnPlayerHealthChanged);
+ this.RegisterEvent(OnPlayerDied);
+ }
+
+ private void OnPlayerHealthChanged(PlayerHealthChangedEvent e)
+ {
+ UpdateHealthBar(e.NewHealth, e.MaxHealth);
+
+ if (e.NewHealth < e.PreviousHealth)
+ {
+ ShowDamageEffect(e.DamagePosition, e.PreviousHealth - e.NewHealth);
+ }
+ }
+
+ private void OnPlayerDied(PlayerDiedEvent e)
+ {
+ HideHealthBar();
+ ShowDeathScreen(e.CauseOfDeath);
+ }
+}
+
+public class AudioController : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ this.RegisterEvent(OnPlayerHealthChanged);
+ this.RegisterEvent(OnPlayerDied);
+ }
+
+ private void OnPlayerHealthChanged(PlayerHealthChangedEvent e)
+ {
+ if (e.NewHealth < e.PreviousHealth)
+ {
+ PlayHurtSound(e.DamageType);
+ }
+ }
+
+ private void OnPlayerDied(PlayerDiedEvent e)
+ {
+ PlayDeathSound();
+ }
+}
+
+// ❌ 避免:一个处理器处理多种不相关的事件
+public class PlayerEventHandler : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ this.RegisterEvent(OnPlayerHealthChanged);
+ this.RegisterEvent(OnPlayerDied);
+ this.RegisterEvent(OnWeaponEquipped);
+ this.RegisterEvent(OnLevelUp);
+ // 注册太多事件,职责混乱
+ }
+
+ private void OnPlayerHealthChanged(PlayerHealthChangedEvent e)
+ {
+ UpdateUI(); // UI职责
+ PlayAudio(); // 音频职责
+ SaveStatistics(); // 存档职责
+ UpdateAchievements(); // 成就系统职责
+ // 一个事件处理器承担太多职责
+ }
+}
+```
+
+## 模块化架构
+
+### 1. 模块边界清晰
+
+```csharp
+// ✅ 好的做法:清晰的模块边界
+public class AudioModule : AbstractModule
+{
+ // 模块只负责音频相关的功能
+ public override void Install(IArchitecture architecture)
+ {
+ architecture.RegisterSystem(new AudioSystem());
+ architecture.RegisterSystem(new MusicSystem());
+ architecture.RegisterUtility(new AudioUtility());
+ }
+}
+
+public class InputModule : AbstractModule
+{
+ // 模块只负责输入相关的功能
+ public override void Install(IArchitecture architecture)
+ {
+ architecture.RegisterSystem(new InputSystem());
+ architecture.RegisterSystem(new InputMappingSystem());
+ architecture.RegisterUtility(new InputUtility());
+ }
+}
+
+public class UIModule : AbstractModule
+{
+ // 模块只负责UI相关的功能
+ public override void Install(IArchitecture architecture)
+ {
+ architecture.RegisterSystem(new UISystem());
+ architecture.RegisterSystem(new HUDSystem());
+ architecture.RegisterSystem(new MenuSystem());
+ architecture.RegisterUtility(new UIUtility());
+ }
+}
+
+// ❌ 避免:模块职责混乱
+public class GameModule : AbstractModule
+{
+ public override void Install(IArchitecture architecture)
+ {
+ // 一个模块包含所有功能
+ architecture.RegisterSystem(new AudioSystem()); // 音频
+ architecture.RegisterSystem(new InputSystem()); // 输入
+ architecture.RegisterSystem(new UISystem()); // UI
+ architecture.RegisterSystem(new CombatSystem()); // 战斗
+ architecture.RegisterSystem(new InventorySystem()); // 背包
+ architecture.RegisterSystem(new QuestSystem()); // 任务
+ // 模块过于庞大,难以维护
+ }
+}
+```
+
+### 2. 模块间通信
+
+```csharp
+// ✅ 好的做法:通过事件进行模块间通信
+public class AudioModule : AbstractModule
+{
+ public override void Install(IArchitecture architecture)
+ {
+ architecture.RegisterSystem(new AudioSystem());
+ }
+}
+
+public class AudioSystem : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ // 监听其他模块发送的事件
+ this.RegisterEvent(OnPlayerAttack);
+ this.RegisterEvent(OnPlayerDied);
+ this.RegisterEvent(OnWeaponEquipped);
+ }
+
+ private void OnPlayerAttack(PlayerAttackEvent e)
+ {
+ PlayAttackSound(e.WeaponType);
+ }
+
+ private void OnPlayerDied(PlayerDiedEvent e)
+ {
+ PlayDeathSound();
+ }
+
+ private void OnWeaponEquipped(WeaponEquippedEvent e)
+ {
+ PlayEquipSound(e.WeaponType);
+ }
+}
+
+public class CombatModule : AbstractModule
+{
+ public override void Install(IArchitecture architecture)
+ {
+ architecture.RegisterSystem(new CombatSystem());
+ }
+}
+
+public class CombatSystem : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ this.RegisterEvent(OnAttackInput);
+ }
+
+ private void OnAttackInput(AttackInputEvent e)
+ {
+ ProcessAttack(e);
+
+ // 发送事件通知其他模块
+ SendEvent(new PlayerAttackEvent {
+ PlayerId = e.PlayerId,
+ WeaponType = GetPlayerWeaponType(e.PlayerId)
+ });
+ }
+}
+
+// ❌ 避免:模块间直接依赖
+public class CombatSystem : AbstractSystem
+{
+ private AudioSystem _audioSystem; // 直接依赖其他模块
+
+ protected override void OnInit()
+ {
+ // 直接获取其他模块的系统
+ _audioSystem = GetSystem();
+ }
+
+ private void OnAttackInput(AttackInputEvent e)
+ {
+ ProcessAttack(e);
+
+ // 直接调用其他模块的方法
+ _audioSystem.PlayAttackSound(weaponType);
+ }
+}
+```
+
+## 错误处理策略
+
+### 1. 异常处理层次
+
+```csharp
+// ✅ 好的做法:分层异常处理
+public class GameApplicationException : Exception
+{
+ public string ErrorCode { get; }
+ public Dictionary Context { get; }
+
+ public GameApplicationException(string message, string errorCode,
+ Dictionary context = null, Exception innerException = null)
+ : base(message, innerException)
+ {
+ ErrorCode = errorCode;
+ Context = context ?? new Dictionary();
+ }
+}
+
+public class PlayerException : GameApplicationException
+{
+ public PlayerException(string message, string errorCode,
+ Dictionary context = null, Exception innerException = null)
+ : base(message, errorCode, context, innerException)
+ {
+ }
+}
+
+public class InventoryException : GameApplicationException
+{
+ public InventoryException(string message, string errorCode,
+ Dictionary context = null, Exception innerException = null)
+ : base(message, errorCode, context, innerException)
+ {
+ }
+}
+
+// 在系统中的使用
+public class PlayerInventorySystem : AbstractSystem
+{
+ public void AddItem(string playerId, Item item)
+ {
+ try
+ {
+ ValidateItem(item);
+ CheckInventorySpace(playerId, item);
+
+ AddItemToInventory(playerId, item);
+
+ SendEvent(new ItemAddedEvent { PlayerId = playerId, Item = item });
+ }
+ catch (ItemValidationException ex)
+ {
+ throw new InventoryException(
+ $"Failed to add item {item.Id} to player {playerId}",
+ "ITEM_VALIDATION_FAILED",
+ new Dictionary
+ {
+ ["playerId"] = playerId,
+ ["itemId"] = item.Id,
+ ["validationError"] = ex.Message
+ },
+ ex
+ );
+ }
+ catch (InventoryFullException ex)
+ {
+ throw new InventoryException(
+ $"Player {playerId} inventory is full",
+ "INVENTORY_FULL",
+ new Dictionary
+ {
+ ["playerId"] = playerId,
+ ["itemId"] = item.Id,
+ ["maxSlots"] = ex.MaxSlots,
+ ["currentSlots"] = ex.CurrentSlots
+ },
+ ex
+ );
+ }
+ catch (Exception ex)
+ {
+ // 捕获未知异常并包装
+ throw new InventoryException(
+ $"Unexpected error adding item {item.Id} to player {playerId}",
+ "UNKNOWN_ERROR",
+ new Dictionary
+ {
+ ["playerId"] = playerId,
+ ["itemId"] = item.Id,
+ ["originalError"] = ex.Message
+ },
+ ex
+ );
+ }
+ }
+
+ private void ValidateItem(Item item)
+ {
+ if (item == null)
+ throw new ItemValidationException("Item cannot be null");
+
+ if (string.IsNullOrEmpty(item.Id))
+ throw new ItemValidationException("Item ID cannot be empty");
+
+ if (item.StackSize <= 0)
+ throw new ItemValidationException("Item stack size must be positive");
+ }
+
+ private void CheckInventorySpace(string playerId, Item item)
+ {
+ var inventory = GetPlayerInventory(playerId);
+ var requiredSpace = CalculateRequiredSpace(item);
+
+ if (inventory.FreeSpace < requiredSpace)
+ {
+ throw new InventoryFullException(
+ inventory.FreeSpace,
+ inventory.MaxSlots
+ );
+ }
+ }
+}
+```
+
+### 2. 错误恢复策略
+
+```csharp
+// ✅ 好的做法:优雅的错误恢复
+public class SaveSystem : AbstractSystem
+{
+ private readonly IStorage _primaryStorage;
+ private readonly IStorage _backupStorage;
+
+ public SaveSystem(IStorage primaryStorage, IStorage backupStorage = null)
+ {
+ _primaryStorage = primaryStorage;
+ _backupStorage = backupStorage ?? new LocalStorage("backup");
+ }
+
+ public async Task LoadSaveDataAsync(string saveId)
+ {
+ try
+ {
+ // 尝试从主存储加载
+ return await _primaryStorage.ReadAsync(saveId);
+ }
+ catch (StorageException ex)
+ {
+ Logger.Warning($"Failed to load from primary storage: {ex.Message}");
+
+ try
+ {
+ // 尝试从备份存储加载
+ var backupData = await _backupStorage.ReadAsync(saveId);
+ Logger.Info($"Successfully loaded from backup storage: {saveId}");
+
+ // 恢复到主存储
+ await _primaryStorage.WriteAsync(saveId, backupData);
+
+ return backupData;
+ }
+ catch (Exception backupEx)
+ {
+ Logger.Error($"Failed to load from backup storage: {backupEx.Message}");
+
+ // 返回默认存档数据
+ return GetDefaultSaveData();
+ }
+ }
+ }
+
+ private SaveData GetDefaultSaveData()
+ {
+ Logger.Warning("Returning default save data due to loading failures");
+ return new SaveData
+ {
+ PlayerId = "default",
+ Level = 1,
+ Health = 100,
+ Position = Vector3.Zero,
+ CreatedAt = DateTime.UtcNow
+ };
+ }
+}
+
+// ❌ 避免:粗暴的错误处理
+public class SaveSystem : AbstractSystem
+{
+ public async Task LoadSaveDataAsync(string saveId)
+ {
+ try
+ {
+ return await _storage.ReadAsync(saveId);
+ }
+ catch (Exception ex)
+ {
+ // 直接抛出异常,不提供恢复机制
+ throw new Exception($"Failed to load save: {ex.Message}", ex);
+ }
+ }
+}
+```
+
+## 测试策略
+
+### 1. 可测试的架构设计
+
+```csharp
+// ✅ 好的做法:可测试的架构
+public interface IPlayerMovementService
+{
+ void MovePlayer(string playerId, Vector2 direction);
+ bool CanPlayerMove(string playerId);
+}
+
+public class PlayerMovementService : IPlayerMovementService
+{
+ private readonly IPlayerRepository _playerRepository;
+ private readonly ICollisionService _collisionService;
+ private readonly IMapService _mapService;
+
+ public PlayerMovementService(
+ IPlayerRepository playerRepository,
+ ICollisionService collisionService,
+ IMapService mapService)
+ {
+ _playerRepository = playerRepository;
+ _collisionService = collisionService;
+ _mapService = mapService;
+ }
+
+ public void MovePlayer(string playerId, Vector2 direction)
+ {
+ if (!CanPlayerMove(playerId))
+ return;
+
+ var player = _playerRepository.GetById(playerId);
+ var newPosition = player.Position + direction * player.Speed;
+
+ if (_collisionService.CanMoveTo(newPosition))
+ {
+ player.Position = newPosition;
+ _playerRepository.Update(player);
+ }
+ }
+
+ public bool CanPlayerMove(string playerId)
+ {
+ var player = _playerRepository.GetById(playerId);
+ return player != null && player.IsAlive && !player.IsStunned;
+ }
+}
+
+// 测试代码
+[TestFixture]
+public class PlayerMovementServiceTests
+{
+ private Mock _mockPlayerRepository;
+ private Mock _mockCollisionService;
+ private Mock _mockMapService;
+ private PlayerMovementService _movementService;
+
+ [SetUp]
+ public void Setup()
+ {
+ _mockPlayerRepository = new Mock();
+ _mockCollisionService = new Mock();
+ _mockMapService = new Mock();
+
+ _movementService = new PlayerMovementService(
+ _mockPlayerRepository.Object,
+ _mockCollisionService.Object,
+ _mockMapService.Object
+ );
+ }
+
+ [Test]
+ public void MovePlayer_ValidMovement_ShouldUpdatePlayerPosition()
+ {
+ // Arrange
+ var playerId = "player1";
+ var player = new Player { Id = playerId, Position = Vector2.Zero, Speed = 5.0f };
+ var direction = Vector2.Right;
+
+ _mockPlayerRepository.Setup(r => r.GetById(playerId)).Returns(player);
+ _mockCollisionService.Setup(c => c.CanMoveTo(It.IsAny())).Returns(true);
+
+ // Act
+ _movementService.MovePlayer(playerId, direction);
+
+ // Assert
+ _mockPlayerRepository.Verify(r => r.Update(It.Is(p => p.Position == Vector2.Right * 5.0f)), Times.Once);
+ }
+
+ [Test]
+ public void MovePlayer_CollisionBlocked_ShouldNotUpdatePlayerPosition()
+ {
+ // Arrange
+ var playerId = "player1";
+ var player = new Player { Id = playerId, Position = Vector2.Zero, Speed = 5.0f };
+ var direction = Vector2.Right;
+
+ _mockPlayerRepository.Setup(r => r.GetById(playerId)).Returns(player);
+ _mockCollisionService.Setup(c => c.CanMoveTo(It.IsAny())).Returns(false);
+
+ // Act
+ _movementService.MovePlayer(playerId, direction);
+
+ // Assert
+ _mockPlayerRepository.Verify(r => r.Update(It.IsAny()), Times.Never);
+ }
+}
+
+// ❌ 避免:难以测试的设计
+public class PlayerMovementSystem : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ this.RegisterEvent(OnMovementInput);
+ }
+
+ private void OnMovementInput(MovementInputEvent e)
+ {
+ var player = GetModel(); // 依赖架构,难以测试
+ var newPosition = player.Position + e.Direction * player.Speed;
+
+ if (CanMoveTo(newPosition)) // 私有方法,难以直接测试
+ {
+ player.Position = newPosition;
+ }
+ }
+
+ private bool CanMoveTo(Vector2 position)
+ {
+ // 复杂的碰撞检测逻辑,难以测试
+ return true;
+ }
+}
+```
+
+## 重构指南
+
+### 1. 识别代码异味
+
+```csharp
+// ❌ 代码异味:长方法、重复代码、上帝类
+public class GameManager : Node
+{
+ public void ProcessPlayerInput(InputEvent @event)
+ {
+ // 长方法 - 做太多事情
+ if (@event is InputEventKey keyEvent && keyEvent.Pressed)
+ {
+ switch (keyEvent.Keycode)
+ {
+ case Key.W:
+ MovePlayer(Vector2.Up);
+ PlayFootstepSound();
+ UpdatePlayerAnimation("walk_up");
+ CheckPlayerCollisions();
+ UpdateCameraPosition();
+ SavePlayerPosition();
+ break;
+ case Key.S:
+ MovePlayer(Vector2.Down);
+ PlayFootstepSound();
+ UpdatePlayerAnimation("walk_down");
+ CheckPlayerCollisions();
+ UpdateCameraPosition();
+ SavePlayerPosition();
+ break;
+ // 重复代码
+ }
+ }
+ }
+
+ private void MovePlayer(Vector2 direction)
+ {
+ Player.Position += direction * Player.Speed;
+ }
+
+ private void PlayFootstepSound()
+ {
+ AudioPlayer.Play("footstep.wav");
+ }
+
+ // ... 更多方法,类过于庞大
+}
+
+// ✅ 重构后:职责分离
+public class PlayerInputController : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ this.RegisterEvent(OnInput);
+ }
+
+ private void OnInput(InputEvent e)
+ {
+ if (e is InputEventKey keyEvent && keyEvent.Pressed)
+ {
+ var direction = GetDirectionFromKey(keyEvent.Keycode);
+ if (direction != Vector2.Zero)
+ {
+ SendEvent(new PlayerMoveEvent { Direction = direction });
+ }
+ }
+ }
+
+ private Vector2 GetDirectionFromKey(Key keycode)
+ {
+ return keycode switch
+ {
+ Key.W => Vector2.Up,
+ Key.S => Vector2.Down,
+ Key.A => Vector2.Left,
+ Key.D => Vector2.Right,
+ _ => Vector2.Zero
+ };
+ }
+}
+
+public class PlayerMovementSystem : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ this.RegisterEvent(OnPlayerMove);
+ }
+
+ private void OnPlayerMove(PlayerMoveEvent e)
+ {
+ var playerModel = GetModel();
+ var newPosition = playerModel.Position + e.Direction * playerModel.Speed;
+
+ if (CanMoveTo(newPosition))
+ {
+ playerModel.Position = newPosition;
+ SendEvent(new PlayerMovedEvent { NewPosition = newPosition });
+ }
+ }
+
+ private bool CanMoveTo(Vector2 position)
+ {
+ var collisionService = GetUtility();
+ return collisionService.CanMoveTo(position);
+ }
+}
+
+public class AudioSystem : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ this.RegisterEvent(OnPlayerMoved);
+ }
+
+ private void OnPlayerMoved(PlayerMovedEvent e)
+ {
+ PlayFootstepSound();
+ }
+
+ private void PlayFootstepSound()
+ {
+ var audioUtility = GetUtility();
+ audioUtility.PlaySound("footstep.wav");
+ }
+}
+
+public class AnimationSystem : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ this.RegisterEvent(OnPlayerMoved);
+ }
+
+ private void OnPlayerMoved(PlayerMovedEvent e)
+ {
+ var animationName = GetAnimationNameFromDirection(e.Direction);
+ SendEvent(new PlayAnimationEvent { AnimationName = animationName });
+ }
+
+ private string GetAnimationNameFromDirection(Vector2 direction)
+ {
+ if (direction == Vector2.Up) return "walk_up";
+ if (direction == Vector2.Down) return "walk_down";
+ if (direction == Vector2.Left) return "walk_left";
+ if (direction == Vector2.Right) return "walk_right";
+ return "idle";
+ }
+}
+```
+
+### 2. 渐进式重构
+
+```csharp
+// 第一步:提取重复代码
+public class PlayerController : Node
+{
+ public void ProcessInput(InputEvent @event)
+ {
+ if (@event is InputEventKey keyEvent && keyEvent.Pressed)
+ {
+ Vector2 direction;
+ switch (keyEvent.Keycode)
+ {
+ case Key.W:
+ direction = Vector2.Up;
+ break;
+ case Key.S:
+ direction = Vector2.Down;
+ break;
+ case Key.A:
+ direction = Vector2.Left;
+ break;
+ case Key.D:
+ direction = Vector2.Right;
+ break;
+ default:
+ return;
+ }
+
+ MovePlayer(direction);
+ }
+ }
+}
+
+// 第二步:提取方法
+public class PlayerController : Node
+{
+ public void ProcessInput(InputEvent @event)
+ {
+ if (@event is InputEventKey keyEvent && keyEvent.Pressed)
+ {
+ var direction = GetDirectionFromKey(keyEvent.Keycode);
+ if (direction != Vector2.Zero)
+ {
+ MovePlayer(direction);
+ }
+ }
+ }
+
+ private Vector2 GetDirectionFromKey(Key keycode)
+ {
+ return keycode switch
+ {
+ Key.W => Vector2.Up,
+ Key.S => Vector2.Down,
+ Key.A => Vector2.Left,
+ Key.D => Vector2.Right,
+ _ => Vector2.Zero
+ };
+ }
+}
+
+// 第三步:引入系统和事件
+public class PlayerController : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ this.RegisterEvent(OnInput);
+ }
+
+ private void OnInput(InputEvent e)
+ {
+ if (e is InputEventKey keyEvent && keyEvent.Pressed)
+ {
+ var direction = GetDirectionFromKey(keyEvent.Keycode);
+ if (direction != Vector2.Zero)
+ {
+ SendEvent(new PlayerMoveEvent { Direction = direction });
+ }
+ }
+ }
+
+ private Vector2 GetDirectionFromKey(Key keycode)
+ {
+ return keycode switch
+ {
+ Key.W => Vector2.Up,
+ Key.S => Vector2.Down,
+ Key.A => Vector2.Left,
+ Key.D => Vector2.Right,
+ _ => Vector2.Zero
+ };
+ }
+}
+```
+
+---
+
+## 模式选择与组合
+
+### 何时使用哪种模式?
+
+#### 小型项目(原型、Demo)
+
+```csharp
+// 推荐组合:MVC + 事件驱动 + 服务定位器
+public class SimpleGameArchitecture : Architecture
+{
+ protected override void Init()
+ {
+ // Model
+ RegisterModel(new PlayerModel());
+ RegisterModel(new GameModel());
+
+ // System
+ RegisterSystem(new GameplaySystem());
+ RegisterSystem(new AudioSystem());
+
+ // 使用服务定位器模式
+ // Controller 通过 this.GetModel/GetSystem 获取服务
+ }
+}
+```
+
+**优势**:
+
+- 快速开发
+- 代码简洁
+- 易于理解
+
+#### 中型项目(独立游戏)
+
+```csharp
+// 推荐组合:MVC + MVVM + 命令/查询 + 事件驱动 + 依赖注入
+public class GameArchitecture : Architecture
+{
+ protected override void Init()
+ {
+ // 注册 Utility(依赖注入)
+ RegisterUtility<IStorageService>(new LocalStorageService());
+ RegisterUtility<IAudioService>(new GodotAudioService());
+
+ // 注册 Model(MVVM)
+ RegisterModel(new PlayerModel());
+ RegisterModel(new PlayerViewModel());
+
+ // 注册 System(命令/查询处理)
+ RegisterSystem(new CombatSystem());
+ RegisterSystem(new InventorySystem());
+
+ // 状态机
+ var stateMachine = new StateMachineSystem();
+ stateMachine
+ .Register(new MenuState())
+ .Register(new GameplayState());
+ RegisterSystem<IStateMachineSystem>(stateMachine);
+ }
+}
+```
+
+**优势**:
+
+- 职责清晰
+- 易于测试
+- 支持团队协作
+
+#### 大型项目(商业游戏)
+
+```csharp
+// 推荐组合:所有模式 + 模块化架构
+public class GameArchitecture : Architecture
+{
+ protected override void Init()
+ {
+ // 模块化安装
+ InstallModule(new CoreModule());
+ InstallModule(new AudioModule());
+ InstallModule(new NetworkModule());
+ InstallModule(new UIModule());
+ InstallModule(new GameplayModule());
+ }
+}
+
+// 核心模块
+public class CoreModule : IArchitectureModule
+{
+ public void Install(IArchitecture architecture)
+ {
+ // 依赖注入
+ architecture.RegisterUtility<IStorageService>(new CloudStorageService());
+ architecture.RegisterUtility<IAnalyticsService>(new AnalyticsService());
+
+ // 对象池
+ architecture.RegisterSystem(new BulletPoolSystem());
+ architecture.RegisterSystem(new ParticlePoolSystem());
+ }
+}
+
+// 游戏玩法模块
+public class GameplayModule : IArchitectureModule
+{
+ public void Install(IArchitecture architecture)
+ {
+ // Model
+ architecture.RegisterModel(new PlayerModel());
+ architecture.RegisterModel(new EnemyModel());
+
+ // System(使用命令/查询模式)
+ architecture.RegisterSystem(new CombatSystem());
+ architecture.RegisterSystem(new MovementSystem());
+
+ // 状态机
+ var stateMachine = new StateMachineSystem();
+ stateMachine
+ .Register(new MenuState())
+ .Register(new LoadingState())
+ .Register(new GameplayState())
+ .Register(new PauseState())
+ .Register(new GameOverState());
+ architecture.RegisterSystem<IStateMachineSystem>(stateMachine);
+ }
+}
+```
+
+**优势**:
+
+- 高度模块化
+- 易于维护和扩展
+- 支持大型团队
+- 完善的测试覆盖
+
+### 模式组合示例
+
+#### 组合 1:MVVM + 命令模式
+
+```csharp
+// ViewModel
+public class ShopViewModel : AbstractModel
+{
+ public BindableProperty<int> PlayerGold { get; } = new(1000);
+ public BindableProperty<bool> CanBuy { get; } = new(true);
+ public BindableProperty<string> StatusMessage { get; } = new("");
+
+ protected override void OnInit()
+ {
+ // 监听购买事件
+ this.RegisterEvent<ItemPurchasedEvent>(OnItemPurchased);
+ this.RegisterEvent<InsufficientGoldEvent>(OnInsufficientGold);
+
+ // 监听金币变化
+ PlayerGold.Register(gold =>
+ {
+ CanBuy.Value = gold >= 100;
+ });
+ }
+
+ private void OnItemPurchased(ItemPurchasedEvent e)
+ {
+ PlayerGold.Value -= e.Cost;
+ StatusMessage.Value = $"购买成功:{e.ItemName}";
+ }
+
+ private void OnInsufficientGold(InsufficientGoldEvent e)
+ {
+ StatusMessage.Value = "金币不足!";
+ }
+}
+
+// View
+public class ShopView : Control
+{
+ private ShopViewModel _viewModel;
+
+ public override void _Ready()
+ {
+ _viewModel = GetModel<ShopViewModel>();
+
+ // 数据绑定
+ _viewModel.PlayerGold.Register(gold =>
+ {
+ GetNode<Label>("GoldLabel").Text = $"金币:{gold}";
+ });
+
+ _viewModel.CanBuy.Register(canBuy =>
+ {
+ GetNode<Button>("BuyButton").Disabled = !canBuy;
+ });
+
+ _viewModel.StatusMessage.Register(msg =>
+ {
+ GetNode<Label>("StatusLabel").Text = msg;
+ });
+ }
+
+ private void OnBuyButtonPressed()
+ {
+ // 发送命令
+ this.SendCommand(new BuyItemCommand
+ {
+ Input = new BuyItemInput { ItemId = "sword_01" }
+ });
+ }
+}
+```
+
+#### 组合 2:状态模式 + 对象池
+
+```csharp
+// 游戏状态使用对象池
+public class GameplayState : ContextAwareStateBase
+{
+ private BulletPoolSystem _bulletPool;
+ private ParticlePoolSystem _particlePool;
+
+ public override void OnEnter(IState from)
+ {
+ // 获取对象池
+ _bulletPool = this.GetSystem<BulletPoolSystem>();
+ _particlePool = this.GetSystem<ParticlePoolSystem>();
+
+ // 预热对象池
+ _bulletPool.PrewarmPool(100);
+ _particlePool.PrewarmPool(200);
+
+ // 注册事件
+ this.RegisterEvent<FireWeaponEvent>(OnFireWeapon);
+ }
+
+ private void OnFireWeapon(FireWeaponEvent e)
+ {
+ // 从池中获取子弹
+ var bullet = _bulletPool.Spawn();
+ bullet.Position = e.Position;
+ bullet.Direction = e.Direction;
+
+ // 生成粒子效果
+ var particle = _particlePool.Spawn();
+ particle.Position = e.Position;
+ }
+
+ public override void OnExit(IState to)
+ {
+ // 回收所有对象
+ _bulletPool.RecycleAll();
+ _particlePool.RecycleAll();
+ }
+}
+```
+
+#### 组合 3:事件驱动 + 查询模式
+
+```csharp
+// 成就系统:监听事件,使用查询验证条件
+public class AchievementSystem : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ this.RegisterEvent<EnemyKilledEvent>(OnEnemyKilled);
+ this.RegisterEvent<LevelCompletedEvent>(OnLevelCompleted);
+ }
+
+ private void OnEnemyKilled(EnemyKilledEvent e)
+ {
+ // 查询击杀总数
+ var query = new GetTotalKillsQuery { Input = new EmptyQueryInput() };
+ var totalKills = this.SendQuery(query);
+
+ // 检查成就
+ if (totalKills == 100)
+ {
+ UnlockAchievement("kill_100_enemies");
+ }
+ }
+
+ private void OnLevelCompleted(LevelCompletedEvent e)
+ {
+ // 查询是否满足完美通关条件
+ var query = new IsPerfectClearQuery
+ {
+ Input = new IsPerfectClearInput { LevelId = e.LevelId }
+ };
+ var isPerfect = this.SendQuery(query);
+
+ if (isPerfect)
+ {
+ UnlockAchievement($"perfect_clear_level_{e.LevelId}");
+ }
+ }
+}
+```
+
+### 模式选择决策树
+
+```
+需要管理游戏状态?
+├─ 是 → 使用状态模式
+└─ 否 → 继续
+
+需要频繁创建/销毁对象?
+├─ 是 → 使用对象池模式
+└─ 否 → 继续
+
+需要解耦组件通信?
+├─ 是 → 使用事件驱动模式
+└─ 否 → 继续
+
+需要封装操作?
+├─ 是 → 使用命令模式
+└─ 否 → 继续
+
+需要分离读写操作?
+├─ 是 → 使用查询模式(CQRS)
+└─ 否 → 继续
+
+需要数据绑定和响应式 UI?
+├─ 是 → 使用 MVVM 模式
+└─ 否 → 使用 MVC 模式
+
+需要管理依赖?
+├─ 大型项目 → 使用依赖注入
+└─ 小型项目 → 使用服务定位器
+```
+
+## 常见问题
+
+### Q1: 应该使用 MVC 还是 MVVM?
+
+**A**: 取决于项目需求:
+
+- **使用 MVC**:
+ - 简单的 UI 更新
+ - 不需要复杂的数据绑定
+ - 快速原型开发
+
+- **使用 MVVM**:
+ - 复杂的数据驱动 UI
+ - 需要自动更新界面
+ - 大量计算属性
+
+**推荐**:可以混合使用,简单界面用 MVC,复杂界面用 MVVM。
+
+### Q2: 命令模式和查询模式有什么区别?
+
+**A**:
+
+| 特性 | 命令模式 | 查询模式 |
+|---------|----------------|---------------------|
+| **目的** | 修改状态 | 读取数据 |
+| **返回值** | 可选 | 必须有 |
+| **副作用** | 有 | 无 |
+| **示例** | BuyItemCommand | GetPlayerStatsQuery |
+
+**原则**:命令改变状态,查询读取状态,两者不混用。
+
+### Q3: 何时使用事件,何时使用命令?
+
+**A**:
+
+- **使用事件**:
+ - 通知状态变化
+ - 一对多通信
+ - 跨模块通信
+ - 不关心处理结果
+
+- **使用命令**:
+ - 执行具体操作
+ - 需要封装逻辑
+ - 需要撤销/重做
+ - 需要返回结果
+
+**示例**:
+
+```csharp
+// 使用命令执行操作
+this.SendCommand(new BuyItemCommand());
+
+// 使用事件通知结果
+this.SendEvent(new ItemPurchasedEvent());
+```
+
+### Q4: 依赖注入和服务定位器哪个更好?
+
+**A**:
+
+- **依赖注入**:
+ - ✅ 依赖关系明确
+ - ✅ 易于测试
+ - ✅ 编译时检查
+ - ❌ 配置复杂
+
+- **服务定位器**:
+ - ✅ 简单直接
+ - ✅ 易于使用
+ - ❌ 依赖隐式
+ - ❌ 难以测试
+
+**推荐**:
+
+- 小项目:服务定位器
+- 大项目:依赖注入
+- 混合使用:核心服务用依赖注入,辅助服务用服务定位器
+
+### Q5: 对象池适合哪些场景?
+
+**A**:
+
+**适合**:
+
+- 频繁创建/销毁的对象(子弹、粒子)
+- 创建成本高的对象(网络连接)
+- 需要稳定帧率的场景
+
+**不适合**:
+
+- 创建频率低的对象
+- 对象状态复杂难以重置
+- 内存受限的场景
+
+**示例**:
+
+```csharp
+// ✅ 适合使用对象池
+- 子弹、导弹
+- 粒子效果
+- UI 元素(列表项)
+- 音效播放器
+
+// ❌ 不适合使用对象池
+- 玩家角色
+- 关卡数据
+- 配置对象
+```
+
+### Q6: 状态机和简单的 if-else 有什么区别?
+
+**A**:
+
+**简单 if-else**:
+
+```csharp
+// ❌ 难以维护
+public void Update()
+{
+ if (gameState == GameState.Menu)
+ {
+ UpdateMenu();
+ }
+ else if (gameState == GameState.Playing)
+ {
+ UpdateGameplay();
+ }
+ else if (gameState == GameState.Paused)
+ {
+ UpdatePause();
+ }
+ // 状态逻辑分散,难以管理
+}
+```
+
+**状态机**:
+
+```csharp
+// ✅ 清晰易维护
+public class MenuState : ContextAwareStateBase
+{
+ public override void OnEnter(IState from)
+ {
+ // 进入菜单的所有逻辑集中在这里
+ }
+
+ public override void OnExit(IState to)
+ {
+ // 退出菜单的所有逻辑集中在这里
+ }
+}
+```
+
+**优势**:
+
+- 状态逻辑封装
+- 易于添加新状态
+- 支持状态转换验证
+- 支持状态历史
+
+### Q7: 如何避免过度设计?
+
+**A**:
+
+**原则**:
+
+1. **从简单开始**:先用最简单的方案
+2. **按需重构**:遇到问题再优化
+3. **YAGNI 原则**:You Aren't Gonna Need It
+
+**示例**:
+
+```csharp
+// 第一版:简单直接
+public class Player
+{
+ public int Health = 100;
+}
+
+// 第二版:需要通知时添加事件
+public class Player
+{
+ private int _health = 100;
+ public int Health
+ {
+ get => _health;
+ set
+ {
+ _health = value;
+ OnHealthChanged?.Invoke(value);
+ }
+ }
+ public event Action<int> OnHealthChanged;
+}
+
+// 第三版:需要更多功能时使用 BindableProperty
+public class PlayerModel : AbstractModel
+{
+ public BindableProperty<int> Health { get; } = new(100);
+}
+```
+
+### Q8: 如何在现有项目中引入这些模式?
+
+**A**:
+
+**渐进式重构**:
+
+1. **第一步:引入事件系统**
+ ```csharp
+ // 替换直接调用为事件
+ // 之前:uiManager.UpdateHealth(health);
+ // 之后:SendEvent(new HealthChangedEvent { Health = health });
+ ```
+
+2. **第二步:提取 Model**
+ ```csharp
+ // 将数据从各处集中到 Model
+ public class PlayerModel : AbstractModel
+ {
+ public BindableProperty<int> Health { get; } = new(100);
+ }
+ ```
+
+3. **第三步:引入命令模式**
+ ```csharp
+ // 封装操作为命令
+ public class HealPlayerCommand : AbstractCommand
+ {
+ protected override void OnExecute()
+ {
+ var player = this.GetModel<PlayerModel>();
+ player.Health.Value = player.MaxHealth.Value;
+ }
+ }
+ ```
+
+4. **第四步:添加查询模式**
+ ```csharp
+ // 分离读操作
+ public class GetPlayerStatsQuery : AbstractQuery<PlayerStats>
+ {
+ protected override PlayerStats OnDo()
+ {
+ // 查询逻辑
+ }
+ }
+ ```
+
+### Q9: 性能会受到影响吗?
+
+**A**:
+
+**影响很小**:
+
+- 事件系统:微秒级开销
+- 命令/查询:几乎无开销
+- IoC 容器:字典查找,O(1)
+
+**优化建议**:
+
+1. **避免频繁事件**:不要每帧发送事件
+2. **缓存查询结果**:复杂查询结果可以缓存
+3. **使用对象池**:减少 GC 压力
+4. **批量操作**:合并多个小操作
+
+**性能对比**:
+
+```csharp
+// 直接调用:~1ns
+player.Health = 100;
+
+// 通过命令:~100ns
+SendCommand(new SetHealthCommand { Health = 100 });
+
+// 差异可以忽略不计,但带来了更好的架构
+```
+
+### Q10: 如何测试使用这些模式的代码?
+
+**A**:
+
+**单元测试示例**:
+
+```csharp
+[Test]
+public void BuyItemCommand_InsufficientGold_ShouldNotBuyItem()
+{
+ // Arrange
+ var architecture = new TestArchitecture();
+ var playerModel = new PlayerModel();
+ playerModel.Gold.Value = 50; // 金币不足
+ architecture.RegisterModel(playerModel);
+
+ var command = new BuyItemCommand
+ {
+ Input = new BuyItemInput { ItemId = "sword", Price = 100 }
+ };
+ command.SetArchitecture(architecture);
+
+ // Act
+ command.Execute();
+
+ // Assert
+ Assert.AreEqual(50, playerModel.Gold.Value); // 金币未变化
+}
+
+[Test]
+public void GetPlayerStatsQuery_ShouldReturnCorrectStats()
+{
+ // Arrange
+ var architecture = new TestArchitecture();
+ var playerModel = new PlayerModel();
+ playerModel.Level.Value = 10;
+ playerModel.Health.Value = 80;
+ architecture.RegisterModel(playerModel);
+
+ var query = new GetPlayerStatsQuery();
+ query.SetArchitecture(architecture);
+
+ // Act
+ var stats = query.Do();
+
+ // Assert
+ Assert.AreEqual(10, stats.Level);
+ Assert.AreEqual(80, stats.Health);
+}
+```
+
+---
+
+## 总结
+
+遵循这些架构模式最佳实践,你将能够构建:
+
+- ✅ **清晰的代码结构** - 易于理解和维护
+- ✅ **松耦合的组件** - 便于测试和扩展
+- ✅ **可重用的模块** - 提高开发效率
+- ✅ **健壮的错误处理** - 提高系统稳定性
+- ✅ **完善的测试覆盖** - 保证代码质量
+
+### 关键要点
+
+1. **从简单开始**:不要过度设计,按需添加模式
+2. **理解每个模式的适用场景**:选择合适的模式解决问题
+3. **模式可以组合使用**:发挥各自优势
+4. **持续重构**:随着项目发展优化架构
+5. **注重可测试性**:好的架构应该易于测试
+
+### 推荐学习路径
+
+1. **入门**:MVC + 事件驱动
+2. **进阶**:命令模式 + 查询模式 + MVVM
+3. **高级**:状态模式 + 对象池 + 依赖注入
+4. **专家**:模块化架构 + 所有模式组合
+
+### 相关资源
+
+- [架构核心文档](/zh-CN/core/architecture)
+- [命令模式文档](/zh-CN/core/command)
+- [查询模式文档](/zh-CN/core/query)
+- [事件系统文档](/zh-CN/core/events)
+- [状态机文档](/zh-CN/core/state-machine)
+- [IoC 容器文档](/zh-CN/core/ioc)
+
+记住,好的架构不是一蹴而就的,需要持续的学习、实践和改进。
+
+---
+
+**文档版本**: 2.0.0
+**最后更新**: 2026-03-07
**作者**: GFramework Team
\ No newline at end of file
diff --git a/docs/zh-CN/best-practices/index.md b/docs/zh-CN/best-practices/index.md
index 4b76286..6ed4b9e 100644
--- a/docs/zh-CN/best-practices/index.md
+++ b/docs/zh-CN/best-practices/index.md
@@ -1,483 +1,491 @@
-# 最佳实践
-
-本文档总结了使用 GFramework 的最佳实践和设计模式。
-
-## 架构设计
-
-### 1. 清晰的职责分离
-
-**原则**:每一层都有明确的职责,不要混淆。
-
-```csharp
-// ✅ 正确的职责分离
-public class PlayerModel : AbstractModel
-{
- // Model:只存储数据
- public BindableProperty Health { get; } = new(100);
- public BindableProperty Score { get; } = new(0);
-}
-
-public class CombatSystem : AbstractSystem
-{
- // System:处理业务逻辑
- protected override void OnInit()
- {
- this.RegisterEvent(OnAttack);
- }
-
- private void OnAttack(AttackEvent e)
- {
- var player = this.GetModel();
- player.Health.Value -= e.Damage;
- }
-}
-
-public class PlayerController : IController
-{
- // Controller:连接 UI 和逻辑
- public void Initialize()
- {
- var player = _architecture.GetModel();
- 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.DoSomething(); // 直接调用
- }
-}
-
-// ✅ 松耦合
-public class SystemA : AbstractSystem
-{
- private void OnEvent(EventA e)
- {
- this.SendEvent(new EventB()); // 发送事件
- }
-}
-
-public class SystemB : AbstractSystem
-{
- protected override void OnInit()
- {
- this.RegisterEvent(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
-{
- protected override Vector2 OnDo()
- {
- // 只查询,不修改
- return this.GetModel().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 { }
-public class GetInventoryItemsQuery : AbstractQuery> { }
-
-// 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();
-
- // 注册事件并添加到注销列表
- this.RegisterEvent(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();
- model.Health.Value -= 1;
-}
-
-// ✅ 高效:缓存引用
-private PlayerModel _playerModel;
-
-public void Initialize()
-{
- _playerModel = _architecture.GetModel();
-}
-
-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 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();
- }
-
- [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();
- Assert.AreEqual(100, player.Health.Value);
-
- // 执行操作
- _architecture.SendCommand(new AttackCommand { Damage = 20 });
-
- // 验证结果
- Assert.AreEqual(80, player.Health.Value);
- }
-}
-```
-
-## 文档
-
-### 1. 代码注释
-
-```csharp
-///
-/// 玩家模型,存储玩家的所有状态数据
-///
-public class PlayerModel : AbstractModel
-{
- ///
- /// 玩家的生命值,使用 BindableProperty 实现响应式更新
- ///
- public BindableProperty 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();
- player.Health.Value -= e.Amount;
- }
-}
-```
-
-### 2. 忘记注销监听器
-
-```csharp
-// ❌ 错误:可能导致内存泄漏
-public void Initialize()
-{
- this.RegisterEvent(OnEvent1); // 未注销
-}
-
-// ✅ 正确
-private IUnRegisterList _unregisterList = new UnRegisterList();
-
-public void Initialize()
-{
- this.RegisterEvent(OnEvent1)
- .AddToUnregisterList(_unregisterList);
-}
-
-public void Cleanup()
-{
- _unregisterList.UnRegisterAll();
-}
-```
-
-### 3. 直接调用其他系统
-
-```csharp
-// ❌ 错误:紧耦合
-public class SystemA : AbstractSystem
-{
- private void OnEvent(EventA e)
- {
- var systemB = this.GetSystem();
- systemB.DoSomething();
- }
-}
-
-// ✅ 正确:使用事件解耦
-public class SystemA : AbstractSystem
-{
- private void OnEvent(EventA e)
- {
- this.SendEvent(new EventB());
- }
-}
-```
-
----
-
-遵循这些最佳实践将帮助你构建可维护、高效、可扩展的应用程序。
+# 最佳实践
+
+本文档总结了使用 GFramework 的最佳实践和设计模式。
+
+## 架构设计
+
+### 1. 清晰的职责分离
+
+**原则**:每一层都有明确的职责,不要混淆。
+
+```csharp
+// ✅ 正确的职责分离
+public class PlayerModel : AbstractModel
+{
+ // Model:只存储数据
+ public BindableProperty Health { get; } = new(100);
+ public BindableProperty Score { get; } = new(0);
+}
+
+public class CombatSystem : AbstractSystem
+{
+ // System:处理业务逻辑
+ protected override void OnInit()
+ {
+ this.RegisterEvent(OnAttack);
+ }
+
+ private void OnAttack(AttackEvent e)
+ {
+ var player = this.GetModel();
+ player.Health.Value -= e.Damage;
+ }
+}
+
+using GFramework.Core.Abstractions.controller;
+using GFramework.SourceGenerators.Abstractions.rule;
+
+[ContextAware]
+public partial class PlayerController : IController
+{
+ // Controller:连接 UI 和逻辑
+ public void Initialize()
+ {
+ var player = Context.GetModel();
+ 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.DoSomething(); // 直接调用
+ }
+}
+
+// ✅ 松耦合
+public class SystemA : AbstractSystem
+{
+ private void OnEvent(EventA e)
+ {
+ this.SendEvent(new EventB()); // 发送事件
+ }
+}
+
+public class SystemB : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ this.RegisterEvent(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
+{
+ protected override Vector2 OnDo()
+ {
+ // 只查询,不修改
+ return this.GetModel().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 { }
+public class GetInventoryItemsQuery : AbstractQuery> { }
+
+// Events:使用 Event 后缀
+public class PlayerDiedEvent : IEvent { }
+public class ItemUsedEvent : IEvent { }
+
+// Controllers:使用 Controller 后缀
+public class PlayerController : IController { }
+
+// Utilities:使用 Utility 后缀
+public class StorageUtility : IUtility { }
+```
+
+## 内存管理
+
+### 1. 正确的注销管理
+
+```csharp
+using GFramework.Core.Abstractions.controller;
+using GFramework.SourceGenerators.Abstractions.rule;
+
+[ContextAware]
+public partial class MyController : IController
+{
+ private IUnRegisterList _unregisterList = new UnRegisterList();
+
+ public void Initialize()
+ {
+ var model = Context.GetModel();
+
+ // 注册事件并添加到注销列表
+ Context.RegisterEvent(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 = Context.GetModel();
+ model.Health.Value -= 1;
+}
+
+// ✅ 高效:缓存引用
+private PlayerModel _playerModel;
+
+public void Initialize()
+{
+ _playerModel = Context.GetModel();
+}
+
+public void Update()
+{
+ _playerModel.Health.Value -= 1;
+}
+```
+
+### 2. 避免频繁的事件创建
+
+```csharp
+// ❌ 低效:每帧创建新事件
+public void Update()
+{
+ Context.SendEvent(new UpdateEvent()); // 频繁分配内存
+}
+
+// ✅ 高效:复用事件或使用对象池
+private UpdateEvent _updateEvent = new UpdateEvent();
+
+public void Update()
+{
+ Context.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 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();
+ }
+
+ [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();
+ Assert.AreEqual(100, player.Health.Value);
+
+ // 执行操作
+ _architecture.SendCommand(new AttackCommand { Damage = 20 });
+
+ // 验证结果
+ Assert.AreEqual(80, player.Health.Value);
+ }
+}
+```
+
+## 文档
+
+### 1. 代码注释
+
+```csharp
+///
+/// 玩家模型,存储玩家的所有状态数据
+///
+public class PlayerModel : AbstractModel
+{
+ ///
+ /// 玩家的生命值,使用 BindableProperty 实现响应式更新
+ ///
+ public BindableProperty 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();
+ player.Health.Value -= e.Amount;
+ }
+}
+```
+
+### 2. 忘记注销监听器
+
+```csharp
+// ❌ 错误:可能导致内存泄漏
+public void Initialize()
+{
+ Context.RegisterEvent(OnEvent1); // 未注销
+}
+
+// ✅ 正确
+private IUnRegisterList _unregisterList = new UnRegisterList();
+
+public void Initialize()
+{
+ Context.RegisterEvent(OnEvent1)
+ .AddToUnregisterList(_unregisterList);
+}
+
+public void Cleanup()
+{
+ _unregisterList.UnRegisterAll();
+}
+```
+
+### 3. 直接调用其他系统
+
+```csharp
+// ❌ 错误:紧耦合
+public class SystemA : AbstractSystem
+{
+ private void OnEvent(EventA e)
+ {
+ var systemB = this.GetSystem();
+ systemB.DoSomething();
+ }
+}
+
+// ✅ 正确:使用事件解耦
+public class SystemA : AbstractSystem
+{
+ private void OnEvent(EventA e)
+ {
+ this.SendEvent(new EventB());
+ }
+}
+```
+
+---
+
+遵循这些最佳实践将帮助你构建可维护、高效、可扩展的应用程序。
diff --git a/docs/zh-CN/best-practices/performance.md b/docs/zh-CN/best-practices/performance.md
index 65e9c57..5923079 100644
--- a/docs/zh-CN/best-practices/performance.md
+++ b/docs/zh-CN/best-practices/performance.md
@@ -1,1359 +1,1364 @@
-# 性能优化指南
-
-> 全面的性能优化策略和最佳实践,帮助你构建高性能的游戏应用。
-
-## 📋 目录
-
-- [概述](#概述)
-- [核心概念](#核心概念)
-- [对象池优化](#对象池优化)
-- [事件系统优化](#事件系统优化)
-- [协程优化](#协程优化)
-- [资源管理优化](#资源管理优化)
-- [ECS 性能优化](#ecs-性能优化)
-- [内存优化](#内存优化)
-- [最佳实践](#最佳实践)
-- [常见问题](#常见问题)
-
-## 概述
-
-性能优化是游戏开发中的关键环节。良好的性能不仅能提供流畅的用户体验,还能降低设备功耗,延长电池寿命。本指南将介绍 GFramework
-中的性能优化策略和最佳实践。
-
-### 性能优化的重要性
-
-- **用户体验** - 流畅的帧率和快速的响应时间
-- **设备兼容性** - 在低端设备上也能良好运行
-- **资源效率** - 降低内存占用和 CPU 使用率
-- **电池寿命** - 减少不必要的计算和内存分配
-
-## 核心概念
-
-### 1. 性能瓶颈
-
-性能瓶颈是指限制系统整体性能的关键因素:
-
-- **CPU 瓶颈** - 过多的计算、复杂的逻辑
-- **内存瓶颈** - 频繁的 GC、内存泄漏
-- **GPU 瓶颈** - 过多的绘制调用、复杂的着色器
-- **I/O 瓶颈** - 频繁的文件读写、网络请求
-
-### 2. 性能指标
-
-关键的性能指标:
-
-- **帧率 (FPS)** - 每秒渲染的帧数,目标 60 FPS
-- **帧时间** - 每帧的处理时间,目标 <16.67ms
-- **内存占用** - 应用程序使用的内存量
-- **GC 频率** - 垃圾回收的频率和耗时
-- **加载时间** - 场景和资源的加载时间
-
-### 3. 优化策略
-
-性能优化的基本策略:
-
-- **测量优先** - 先测量,再优化
-- **找到瓶颈** - 使用性能分析工具定位问题
-- **渐进优化** - 逐步优化,避免过早优化
-- **权衡取舍** - 在性能和可维护性之间找到平衡
-
-## 对象池优化
-
-对象池是减少 GC 压力的有效手段,通过复用对象避免频繁的内存分配和释放。
-
-### 1. 使用对象池系统
-
-```csharp
-// ✅ 好的做法:使用对象池
-public class BulletPoolSystem : AbstractObjectPoolSystem<string, Bullet>
-{
- protected override Bullet Create(string key)
- {
- // 创建新的子弹对象
- var bullet = new Bullet();
- bullet.Initialize(key);
- return bullet;
- }
-}
-
-public class Bullet : IPoolableObject
-{
- public string Type { get; private set; }
- public Vector2 Position { get; set; }
- public Vector2 Velocity { get; set; }
- public bool IsActive { get; private set; }
-
- public void Initialize(string type)
- {
- Type = type;
- }
-
- public void OnAcquire()
- {
- // 从池中获取时重置状态
- IsActive = true;
- Position = Vector2.Zero;
- Velocity = Vector2.Zero;
- }
-
- public void OnRelease()
- {
- // 归还到池中时清理状态
- IsActive = false;
- }
-
- public void OnPoolDestroy()
- {
- // 对象被销毁时的清理
- }
-}
-
-// 使用对象池
-public class CombatSystem : AbstractSystem
-{
- private BulletPoolSystem _bulletPool;
-
- protected override void OnInit()
- {
- _bulletPool = GetSystem<BulletPoolSystem>();
-
- // 预热对象池
- _bulletPool.Prewarm("normal_bullet", 50);
- _bulletPool.Prewarm("fire_bullet", 20);
- }
-
- private void FireBullet(string bulletType, Vector2 position, Vector2 direction)
- {
- // 从池中获取子弹
- var bullet = _bulletPool.Acquire(bulletType);
- bullet.Position = position;
- bullet.Velocity = direction * 10f;
-
- // 使用完毕后归还
- // bullet 会在生命周期结束时自动归还
- }
-}
-
-// ❌ 避免:频繁创建和销毁对象
-public class CombatSystem : AbstractSystem
-{
- private void FireBullet(string bulletType, Vector2 position, Vector2 direction)
- {
- // 每次都创建新对象,产生大量 GC
- var bullet = new Bullet();
- bullet.Type = bulletType;
- bullet.Position = position;
- bullet.Velocity = direction * 10f;
-
- // 使用完毕后直接丢弃,等待 GC 回收
- }
-}
-```
-
-### 2. StringBuilder 池
-
-GFramework 提供了 `StringBuilderPool` 用于高效的字符串构建:
-
-```csharp
-// ✅ 好的做法:使用 StringBuilderPool
-public string FormatPlayerInfo(Player player)
-{
- using var sb = StringBuilderPool.GetScoped();
- sb.Value.Append("Player: ");
- sb.Value.Append(player.Name);
- sb.Value.Append(", Level: ");
- sb.Value.Append(player.Level);
- sb.Value.Append(", HP: ");
- sb.Value.Append(player.Health);
- sb.Value.Append("/");
- sb.Value.Append(player.MaxHealth);
- return sb.Value.ToString();
-}
-
-// 或者手动管理
-public string FormatPlayerInfo(Player player)
-{
- var sb = StringBuilderPool.Rent();
- try
- {
- sb.Append("Player: ").Append(player.Name);
- sb.Append(", Level: ").Append(player.Level);
- sb.Append(", HP: ").Append(player.Health).Append("/").Append(player.MaxHealth);
- return sb.ToString();
- }
- finally
- {
- StringBuilderPool.Return(sb);
- }
-}
-
-// ❌ 避免:频繁的字符串拼接
-public string FormatPlayerInfo(Player player)
-{
- // 每次拼接都会创建新的字符串对象
- return "Player: " + player.Name +
- ", Level: " + player.Level +
- ", HP: " + player.Health + "/" + player.MaxHealth;
-}
-```
-
-### 3. ArrayPool 优化
-
-使用 `ArrayPool` 避免频繁的数组分配:
-
-```csharp
-// ✅ 好的做法:使用 ArrayPool
-public void ProcessEntities(List<Entity> entities)
-{
- using var scopedArray = ArrayPool<Entity>.Shared.GetScoped(entities.Count);
- var array = scopedArray.Array;
-
- // 复制到数组进行处理
- entities.CopyTo(array, 0);
-
- // 处理数组
- for (int i = 0; i < entities.Count; i++)
- {
- ProcessEntity(array[i]);
- }
-
- // 自动归还到池中
-}
-
-// ❌ 避免:频繁创建数组
-public void ProcessEntities(List<Entity> entities)
-{
- // 每次都创建新数组
- var array = entities.ToArray();
-
- foreach (var entity in array)
- {
- ProcessEntity(entity);
- }
-
- // 数组等待 GC 回收
-}
-```
-
-### 4. 对象池统计
-
-监控对象池的使用情况:
-
-```csharp
-public class PoolMonitorSystem : AbstractSystem
-{
- private BulletPoolSystem _bulletPool;
-
- protected override void OnInit()
- {
- _bulletPool = GetSystem<BulletPoolSystem>();
- }
-
- public void LogPoolStatistics(string poolKey)
- {
- var stats = _bulletPool.GetStatistics(poolKey);
-
- Logger.Info($"Pool Statistics for '{poolKey}':");
- Logger.Info($" Available: {stats.AvailableCount}");
- Logger.Info($" Active: {stats.ActiveCount}");
- Logger.Info($" Total Created: {stats.TotalCreated}");
- Logger.Info($" Total Acquired: {stats.TotalAcquired}");
- Logger.Info($" Total Released: {stats.TotalReleased}");
- Logger.Info($" Total Destroyed: {stats.TotalDestroyed}");
-
- // 检查是否需要调整池大小
- if (stats.TotalDestroyed > stats.TotalCreated * 0.5)
- {
- Logger.Warning($"Pool '{poolKey}' has high destruction rate, consider increasing max capacity");
- }
- }
-}
-```
-
-## 事件系统优化
-
-事件系统是游戏架构的核心,优化事件处理可以显著提升性能。
-
-### 1. 避免事件订阅泄漏
-
-```csharp
-// ✅ 好的做法:正确管理事件订阅
-public class PlayerController : Node, IController
-{
- private IUnRegisterList _unRegisterList = new UnRegisterList();
- private PlayerModel _playerModel;
-
- public void Initialize(IArchitectureContext context)
- {
- _playerModel = context.GetModel<PlayerModel>();
-
- // 使用 UnRegisterList 管理订阅
- context.RegisterEvent<PlayerDamagedEvent>(OnPlayerDamaged)
- .AddTo(_unRegisterList);
-
- _playerModel.Health.Register(OnHealthChanged)
- .AddTo(_unRegisterList);
- }
-
- public void Cleanup()
- {
- // 统一取消所有订阅
- _unRegisterList.UnRegisterAll();
- }
-
- private void OnPlayerDamaged(PlayerDamagedEvent e) { }
- private void OnHealthChanged(int health) { }
-}
-
-// ❌ 避免:忘记取消订阅
-public class PlayerController : Node, IController
-{
- public void Initialize(IArchitectureContext context)
- {
- // 订阅事件但从不取消订阅
- context.RegisterEvent<PlayerDamagedEvent>(OnPlayerDamaged);
-
- var playerModel = context.GetModel<PlayerModel>();
- playerModel.Health.Register(OnHealthChanged);
-
- // 当对象被销毁时,这些订阅仍然存在,导致内存泄漏
- }
-}
-```
-
-### 2. 使用结构体事件
-
-使用值类型事件避免堆分配:
-
-```csharp
-// ✅ 好的做法:使用结构体事件
-public struct PlayerMovedEvent
-{
- public string PlayerId { get; init; }
- public Vector2 OldPosition { get; init; }
- public Vector2 NewPosition { get; init; }
- public float DeltaTime { get; init; }
-}
-
-public class MovementSystem : AbstractSystem
-{
- private void NotifyPlayerMoved(string playerId, Vector2 oldPos, Vector2 newPos, float deltaTime)
- {
- // 结构体在栈上分配,无 GC 压力
- SendEvent(new PlayerMovedEvent
- {
- PlayerId = playerId,
- OldPosition = oldPos,
- NewPosition = newPos,
- DeltaTime = deltaTime
- });
- }
-}
-
-// ❌ 避免:使用类事件
-public class PlayerMovedEvent
-{
- public string PlayerId { get; set; }
- public Vector2 OldPosition { get; set; }
- public Vector2 NewPosition { get; set; }
- public float DeltaTime { get; set; }
-}
-
-// 每次发送事件都会在堆上分配对象
-```
-
-### 3. 批量事件处理
-
-对于高频事件,考虑批量处理:
-
-```csharp
-// ✅ 好的做法:批量处理事件
-public class DamageSystem : AbstractSystem
-{
- private readonly List<DamageInfo> _pendingDamages = new();
- private float _batchInterval = 0.1f;
- private float _timeSinceLastBatch = 0f;
-
- public void Update(float deltaTime)
- {
- _timeSinceLastBatch += deltaTime;
-
- if (_timeSinceLastBatch >= _batchInterval)
- {
- ProcessDamageBatch();
- _timeSinceLastBatch = 0f;
- }
- }
-
- public void QueueDamage(string entityId, int damage, DamageType type)
- {
- _pendingDamages.Add(new DamageInfo
- {
- EntityId = entityId,
- Damage = damage,
- Type = type
- });
- }
-
- private void ProcessDamageBatch()
- {
- if (_pendingDamages.Count == 0)
- return;
-
- // 批量处理所有伤害
- foreach (var damageInfo in _pendingDamages)
- {
- ApplyDamage(damageInfo);
- }
-
- // 发送单个批量事件
- SendEvent(new DamageBatchProcessedEvent
- {
- DamageCount = _pendingDamages.Count,
- TotalDamage = _pendingDamages.Sum(d => d.Damage)
- });
-
- _pendingDamages.Clear();
- }
-}
-
-// ❌ 避免:每次都立即处理
-public class DamageSystem : AbstractSystem
-{
- public void ApplyDamage(string entityId, int damage, DamageType type)
- {
- // 每次伤害都立即处理并发送事件
- ProcessDamage(entityId, damage, type);
- SendEvent(new DamageAppliedEvent { EntityId = entityId, Damage = damage });
- }
-}
-```
-
-### 4. 事件优先级优化
-
-合理使用事件优先级避免不必要的处理:
-
-```csharp
-// ✅ 好的做法:使用优先级控制事件传播
-public class InputSystem : AbstractSystem
-{
- protected override void OnInit()
- {
- // UI 输入处理器优先级最高
- this.RegisterEvent<InputEvent>(OnUIInput, priority: 100);
- }
-
- private void OnUIInput(InputEvent e)
- {
- if (IsUIHandlingInput())
- {
- // 停止事件传播,避免游戏逻辑处理
- e.StopPropagation();
- }
- }
-}
-
-public class GameplayInputSystem : AbstractSystem
-{
- protected override void OnInit()
- {
- // 游戏逻辑输入处理器优先级较低
- this.RegisterEvent<InputEvent>(OnGameplayInput, priority: 50);
- }
-
- private void OnGameplayInput(InputEvent e)
- {
- // 如果 UI 已经处理了输入,这里不会执行
- if (!e.IsPropagationStopped)
- {
- ProcessGameplayInput(e);
- }
- }
-}
-```
-
-## 协程优化
-
-协程是处理异步逻辑的强大工具,但不当使用会影响性能。
-
-### 1. 避免过度嵌套
-
-```csharp
-// ✅ 好的做法:扁平化协程结构
-public IEnumerator<IYieldInstruction> LoadGameSequence()
-{
- // 显示加载界面
- yield return ShowLoadingScreen();
-
- // 加载配置
- yield return LoadConfiguration();
-
- // 加载资源
- yield return LoadResources();
-
- // 初始化系统
- yield return InitializeSystems();
-
- // 隐藏加载界面
- yield return HideLoadingScreen();
-}
-
-private IEnumerator<IYieldInstruction> LoadConfiguration()
-{
- var config = await ConfigManager.LoadAsync();
- ApplyConfiguration(config);
- yield break;
-}
-
-// ❌ 避免:深度嵌套
-public IEnumerator<IYieldInstruction> LoadGameSequence()
-{
- yield return ShowLoadingScreen().Then(() =>
- {
- return LoadConfiguration().Then(() =>
- {
- return LoadResources().Then(() =>
- {
- return InitializeSystems().Then(() =>
- {
- return HideLoadingScreen();
- });
- });
- });
- });
-}
-```
-
-### 2. 协程池化
-
-对于频繁启动的协程,考虑复用:
-
-```csharp
-// ✅ 好的做法:复用协程逻辑
-public class EffectSystem : AbstractSystem
-{
- private readonly Dictionary<string, IEnumerator<IYieldInstruction>> _effectCoroutines = new();
-
- public CoroutineHandle PlayEffect(string effectId, Vector2 position)
- {
- // 复用协程逻辑
- return this.StartCoroutine(EffectCoroutine(effectId, position));
- }
-
- private IEnumerator<IYieldInstruction> EffectCoroutine(string effectId, Vector2 position)
- {
- var effect = CreateEffect(effectId, position);
-
- // 播放效果
- yield return new Delay(effect.Duration);
-
- // 清理效果
- DestroyEffect(effect);
- }
-}
-```
-
-### 3. 合理使用 WaitForFrames
-
-```csharp
-// ✅ 好的做法:使用 WaitForFrames 分帧处理
-public IEnumerator<IYieldInstruction> ProcessLargeDataSet(List<Data> dataSet)
-{
- const int batchSize = 100;
-
- for (int i = 0; i < dataSet.Count; i += batchSize)
- {
- int end = Math.Min(i + batchSize, dataSet.Count);
-
- // 处理一批数据
- for (int j = i; j < end; j++)
- {
- ProcessData(dataSet[j]);
- }
-
- // 等待一帧,避免卡顿
- yield return new WaitOneFrame();
- }
-}
-
-// ❌ 避免:一次性处理大量数据
-public void ProcessLargeDataSet(List<Data> dataSet)
-{
- // 一次性处理所有数据,可能导致帧率下降
- foreach (var data in dataSet)
- {
- ProcessData(data);
- }
-}
-```
-
-### 4. 协程取消优化
-
-```csharp
-// ✅ 好的做法:及时取消不需要的协程
-public class AnimationController : AbstractSystem
-{
- private CoroutineHandle _currentAnimation;
-
- public void PlayAnimation(string animationName)
- {
- // 取消当前动画
- if (_currentAnimation.IsValid)
- {
- this.StopCoroutine(_currentAnimation);
- }
-
- // 播放新动画
- _currentAnimation = this.StartCoroutine(AnimationCoroutine(animationName));
- }
-
- private IEnumerator<IYieldInstruction> AnimationCoroutine(string animationName)
- {
- var animation = GetAnimation(animationName);
-
- while (!animation.IsComplete)
- {
- animation.Update(Time.DeltaTime);
- yield return new WaitOneFrame();
- }
- }
-}
-```
-
-## 资源管理优化
-
-高效的资源管理可以显著减少加载时间和内存占用。
-
-### 1. 资源预加载
-
-```csharp
-// ✅ 好的做法:预加载常用资源
-public class ResourcePreloader : AbstractSystem
-{
- private IResourceManager _resourceManager;
-
- protected override void OnInit()
- {
- _resourceManager = GetUtility<IResourceManager>();
- }
-
- public async Task PreloadCommonResources()
- {
- // 预加载 UI 资源
- await _resourceManager.PreloadAsync<Texture>("ui/button_normal");
- await _resourceManager.PreloadAsync<Texture>("ui/button_pressed");
- await _resourceManager.PreloadAsync<Texture>("ui/button_hover");
-
- // 预加载音效
- await _resourceManager.PreloadAsync<AudioClip>("sfx/button_click");
- await _resourceManager.PreloadAsync<AudioClip>("sfx/button_hover");
-
- // 预加载特效
- await _resourceManager.PreloadAsync<ParticleSystem>("effects/hit_effect");
- await _resourceManager.PreloadAsync<ParticleSystem>("effects/explosion");
- }
-}
-```
-
-### 2. 异步加载
-
-```csharp
-// ✅ 好的做法:使用异步加载避免阻塞
-public class SceneLoader : AbstractSystem
-{
- private IResourceManager _resourceManager;
-
- public async Task LoadSceneAsync(string sceneName)
- {
- // 显示加载进度
- var progress = 0f;
- UpdateLoadingProgress(progress);
-
- // 异步加载场景资源
- var sceneData = await _resourceManager.LoadAsync<SceneData>($"scenes/{sceneName}");
- progress += 0.3f;
- UpdateLoadingProgress(progress);
-
- // 异步加载场景依赖的资源
- await LoadSceneDependencies(sceneData);
- progress += 0.5f;
- UpdateLoadingProgress(progress);
-
- // 初始化场景
- await InitializeScene(sceneData);
- progress = 1f;
- UpdateLoadingProgress(progress);
- }
-
- private async Task LoadSceneDependencies(SceneData sceneData)
- {
- var tasks = new List<Task>();
-
- foreach (var dependency in sceneData.Dependencies)
- {
- tasks.Add(_resourceManager.LoadAsync<object>(dependency));
- }
-
- await Task.WhenAll(tasks);
- }
-}
-
-// ❌ 避免:同步加载阻塞主线程
-public class SceneLoader : AbstractSystem
-{
- public void LoadScene(string sceneName)
- {
- // 同步加载会阻塞主线程,导致卡顿
- var sceneData = _resourceManager.Load<SceneData>($"scenes/{sceneName}");
- LoadSceneDependencies(sceneData);
- InitializeScene(sceneData);
- }
-}
-```
-
-### 3. 资源引用计数
-
-```csharp
-// ✅ 好的做法:使用资源句柄管理引用
-public class EntityRenderer : AbstractSystem
-{
- private readonly Dictionary<string, IResourceHandle<Texture>> _textureHandles = new();
-
- public void LoadTexture(string entityId, string texturePath)
- {
- // 获取资源句柄
- var handle = _resourceManager.GetHandle<Texture>(texturePath);
- if (handle != null)
- {
- _textureHandles[entityId] = handle;
- }
- }
-
- public void UnloadTexture(string entityId)
- {
- if (_textureHandles.TryGetValue(entityId, out var handle))
- {
- // 释放句柄,自动管理引用计数
- handle.Dispose();
- _textureHandles.Remove(entityId);
- }
- }
-
- protected override void OnDestroy()
- {
- // 清理所有句柄
- foreach (var handle in _textureHandles.Values)
- {
- handle.Dispose();
- }
- _textureHandles.Clear();
- }
-}
-```
-
-### 4. 资源缓存策略
-
-```csharp
-// ✅ 好的做法:使用合适的释放策略
-public class GameResourceManager : AbstractSystem
-{
- private IResourceManager _resourceManager;
-
- protected override void OnInit()
- {
- _resourceManager = GetUtility<IResourceManager>();
-
- // 设置自动释放策略
- _resourceManager.SetReleaseStrategy(new AutoReleaseStrategy());
- }
-
- public void OnSceneChanged()
- {
- // 场景切换时卸载未使用的资源
- UnloadUnusedResources();
- }
-
- private void UnloadUnusedResources()
- {
- var loadedPaths = _resourceManager.GetLoadedResourcePaths().ToList();
-
- foreach (var path in loadedPaths)
- {
- // 检查资源是否仍在使用
- if (!IsResourceInUse(path))
- {
- _resourceManager.Unload(path);
- }
- }
- }
-
- private bool IsResourceInUse(string path)
- {
- // 检查资源引用计数
- return false; // 实现具体逻辑
- }
-}
-```
-
-## ECS 性能优化
-
-Entity Component System (ECS) 是高性能游戏架构的关键。
-
-### 1. 组件设计优化
-
-```csharp
-// ✅ 好的做法:使用值类型组件
-public struct Position
-{
- public float X;
- public float Y;
- public float Z;
-}
-
-public struct Velocity
-{
- public float X;
- public float Y;
- public float Z;
-}
-
-public struct Health
-{
- public int Current;
- public int Max;
-}
-
-// ❌ 避免:使用引用类型组件
-public class Position
-{
- public float X { get; set; }
- public float Y { get; set; }
- public float Z { get; set; }
-}
-```
-
-### 2. 查询优化
-
-```csharp
-// ✅ 好的做法:使用高效的查询
-public class MovementSystem : ArchSystemAdapter
-{
- private QueryDescription _movementQuery;
-
- public override void Initialize()
- {
- // 预先构建查询
- _movementQuery = new QueryDescription()
- .WithAll<Position, Velocity>()
- .WithNone<Frozen>();
- }
-
- public override void Update(float deltaTime)
- {
- // 使用预构建的查询
- World.Query(in _movementQuery, (ref Position pos, ref Velocity vel) =>
- {
- pos.X += vel.X * deltaTime;
- pos.Y += vel.Y * deltaTime;
- pos.Z += vel.Z * deltaTime;
- });
- }
-}
-
-// ❌ 避免:每帧构建查询
-public class MovementSystem : ArchSystemAdapter
-{
- public override void Update(float deltaTime)
- {
- // 每帧都构建新查询,性能差
- var query = new QueryDescription()
- .WithAll<Position, Velocity>()
- .WithNone<Frozen>();
-
- World.Query(in query, (ref Position pos, ref Velocity vel) =>
- {
- pos.X += vel.X * deltaTime;
- pos.Y += vel.Y * deltaTime;
- pos.Z += vel.Z * deltaTime;
- });
- }
-}
-```
-
-### 3. 批量处理
-
-```csharp
-// ✅ 好的做法:批量处理实体
-public class DamageSystem : ArchSystemAdapter
-{
- private readonly List<(EntityReference entity, int damage)> _pendingDamages = new();
-
- public void QueueDamage(EntityReference entity, int damage)
- {
- _pendingDamages.Add((entity, damage));
- }
-
- public override void Update(float deltaTime)
- {
- if (_pendingDamages.Count == 0)
- return;
-
- // 批量应用伤害
- foreach (var (entity, damage) in _pendingDamages)
- {
- if (World.IsAlive(entity))
- {
- ref var health = ref World.Get<Health>(entity);
- health.Current = Math.Max(0, health.Current - damage);
-
- if (health.Current == 0)
- {
- World.Destroy(entity);
- }
- }
- }
-
- _pendingDamages.Clear();
- }
-}
-```
-
-### 4. 避免装箱
-
-```csharp
-// ✅ 好的做法:避免装箱操作
-public struct EntityId : IEquatable<EntityId>
-{
- public int Value;
-
- public bool Equals(EntityId other) => Value == other.Value;
- public override bool Equals(object obj) => obj is EntityId other && Equals(other);
- public override int GetHashCode() => Value;
-}
-
-// 使用泛型避免装箱
-public class EntityCache<T> where T : struct
-{
- private readonly Dictionary<EntityId, T> _cache = new();
-
- public void Add(EntityId id, T data)
- {
- _cache[id] = data; // 无装箱
- }
-
- public bool TryGet(EntityId id, out T data)
- {
- return _cache.TryGetValue(id, out data); // 无装箱
- }
-}
-
-// ❌ 避免:导致装箱的操作
-public class EntityCache
-{
- private readonly Dictionary<int, object> _cache = new();
-
- public void Add(int id, object data)
- {
- _cache[id] = data; // 值类型会装箱
- }
-}
-```
-
-## 内存优化
-
-减少内存分配和 GC 压力是性能优化的重要方面。
-
-### 1. 使用 Span<T>
-
-```csharp
-// ✅ 好的做法:使用 Span 避免分配
-public void ProcessData(ReadOnlySpan<byte> data)
-{
- // 直接在栈上处理,无堆分配
- Span<int> results = stackalloc int[data.Length];
-
- for (int i = 0; i < data.Length; i++)
- {
- results[i] = ProcessByte(data[i]);
- }
-
- // 使用结果
- UseResults(results);
-}
-
-// 解析字符串避免分配
-public bool TryParseValue(ReadOnlySpan<char> input, out int result)
-{
- return int.TryParse(input, out result);
-}
-
-// ❌ 避免:不必要的数组分配
-public void ProcessData(byte[] data)
-{
- // 创建新数组,产生 GC
- var results = new int[data.Length];
-
- for (int i = 0; i < data.Length; i++)
- {
- results[i] = ProcessByte(data[i]);
- }
-
- UseResults(results);
-}
-```
-
-### 2. 结构体优化
-
-```csharp
-// ✅ 好的做法:使用 readonly struct
-public readonly struct Vector2D
-{
- public readonly float X;
- public readonly float Y;
-
- public Vector2D(float x, float y)
- {
- X = x;
- Y = y;
- }
-
- public float Length() => MathF.Sqrt(X * X + Y * Y);
-
- public Vector2D Normalized()
- {
- var length = Length();
- return length > 0 ? new Vector2D(X / length, Y / length) : this;
- }
-}
-
-// ❌ 避免:可变结构体
-public struct Vector2D
-{
- public float X { get; set; }
- public float Y { get; set; }
-
- // 可变结构体可能导致意外的复制
-}
-```
-
-### 3. 避免闭包分配
-
-```csharp
-// ✅ 好的做法:避免闭包捕获
-public class EventProcessor : AbstractSystem
-{
- private readonly Action<PlayerEvent> _cachedHandler;
-
- public EventProcessor()
- {
- // 缓存委托,避免每次分配
- _cachedHandler = HandlePlayerEvent;
- }
-
- protected override void OnInit()
- {
- this.RegisterEvent(_cachedHandler);
- }
-
- private void HandlePlayerEvent(PlayerEvent e)
- {
- ProcessEvent(e);
- }
-}
-
-// ❌ 避免:每次都创建新的闭包
-public class EventProcessor : AbstractSystem
-{
- protected override void OnInit()
- {
- // 每次都创建新的委托和闭包
- this.RegisterEvent<PlayerEvent>(e =>
- {
- ProcessEvent(e);
- });
- }
-}
-```
-
-### 4. 字符串优化
-
-```csharp
-// ✅ 好的做法:减少字符串分配
-public class Logger
-{
- private readonly StringBuilder _sb = new();
-
- public void LogFormat(string format, params object[] args)
- {
- _sb.Clear();
- _sb.AppendFormat(format, args);
- Log(_sb.ToString());
- }
-
- // 使用字符串插值的优化版本
- public void LogInterpolated(ref DefaultInterpolatedStringHandler handler)
- {
- Log(handler.ToStringAndClear());
- }
-}
-
-// 使用 string.Create 避免中间分配
-public string CreateEntityName(int id, string type)
-{
- return string.Create(type.Length + 10, (id, type), (span, state) =>
- {
- state.type.AsSpan().CopyTo(span);
- span = span.Slice(state.type.Length);
- span[0] = '_';
- state.id.TryFormat(span.Slice(1), out _);
- });
-}
-
-// ❌ 避免:频繁的字符串拼接
-public string CreateEntityName(int id, string type)
-{
- return type + "_" + id.ToString(); // 创建多个临时字符串
-}
-```
-
-## 最佳实践
-
-### 1. 性能测试
-
-```csharp
-// ✅ 使用性能测试验证优化效果
-[TestFixture]
-public class PerformanceTests
-{
- [Test]
- [Performance]
- public void ObjectPool_Performance_Test()
- {
- var pool = new BulletPoolSystem();
- pool.Prewarm("bullet", 1000);
-
- Measure.Method(() =>
- {
- var bullet = pool.Acquire("bullet");
- pool.Release("bullet", bullet);
- })
- .WarmupCount(10)
- .MeasurementCount(100)
- .Run();
- }
-
- [Test]
- public void CompareAllocationMethods()
- {
- // 测试对象池
- var poolTime = MeasureTime(() =>
- {
- var pool = ArrayPool<int>.Shared;
- var array = pool.Rent(1000);
- pool.Return(array);
- });
-
- // 测试直接分配
- var allocTime = MeasureTime(() =>
- {
- var array = new int[1000];
- });
-
- Assert.Less(poolTime, allocTime, "Object pool should be faster");
- }
-
- private long MeasureTime(Action action)
- {
- var sw = Stopwatch.StartNew();
- for (int i = 0; i < 10000; i++)
- {
- action();
- }
- sw.Stop();
- return sw.ElapsedMilliseconds;
- }
-}
-```
-
-### 2. 性能监控
-
-```csharp
-// ✅ 实现性能监控系统
-public class PerformanceMonitor : AbstractSystem
-{
- private readonly Dictionary<string, PerformanceMetric> _metrics = new();
- private float _updateInterval = 1.0f;
- private float _timeSinceUpdate = 0f;
-
- public void Update(float deltaTime)
- {
- _timeSinceUpdate += deltaTime;
-
- if (_timeSinceUpdate >= _updateInterval)
- {
- UpdateMetrics();
- _timeSinceUpdate = 0f;
- }
- }
-
- public void RecordMetric(string name, float value)
- {
- if (!_metrics.TryGetValue(name, out var metric))
- {
- metric = new PerformanceMetric(name);
- _metrics[name] = metric;
- }
-
- metric.AddSample(value);
- }
-
- private void UpdateMetrics()
- {
- foreach (var metric in _metrics.Values)
- {
- Logger.Info($"{metric.Name}: Avg={metric.Average:F2}ms, " +
- $"Min={metric.Min:F2}ms, Max={metric.Max:F2}ms");
- metric.Reset();
- }
- }
-}
-
-public class PerformanceMetric
-{
- public string Name { get; }
- public float Average => _count > 0 ? _sum / _count : 0;
- public float Min { get; private set; } = float.MaxValue;
- public float Max { get; private set; } = float.MinValue;
-
- private float _sum;
- private int _count;
-
- public PerformanceMetric(string name)
- {
- Name = name;
- }
-
- public void AddSample(float value)
- {
- _sum += value;
- _count++;
- Min = Math.Min(Min, value);
- Max = Math.Max(Max, value);
- }
-
- public void Reset()
- {
- _sum = 0;
- _count = 0;
- Min = float.MaxValue;
- Max = float.MinValue;
- }
-}
-```
-
-### 3. 性能分析工具
-
-使用性能分析工具定位瓶颈:
-
-- **Unity Profiler** - Unity 内置的性能分析工具
-- **Godot Profiler** - Godot 的性能监控工具
-- **dotTrace** - JetBrains 的 .NET 性能分析器
-- **PerfView** - Microsoft 的性能分析工具
-
-### 4. 性能优化清单
-
-在优化性能时,遵循以下清单:
-
-- [ ] 使用对象池减少 GC 压力
-- [ ] 正确管理事件订阅,避免内存泄漏
-- [ ] 使用结构体事件避免堆分配
-- [ ] 合理使用协程,避免过度嵌套
-- [ ] 异步加载资源,避免阻塞主线程
-- [ ] 使用 ECS 架构提高数据局部性
-- [ ] 使用 Span<T> 和 stackalloc 减少分配
-- [ ] 避免装箱操作
-- [ ] 缓存常用的委托和对象
-- [ ] 批量处理高频操作
-- [ ] 定期进行性能测试和监控
-
-## 常见问题
-
-### Q1: 什么时候应该使用对象池?
-
-**A**: 当满足以下条件时考虑使用对象池:
-
-- 对象创建成本高(如包含复杂初始化逻辑)
-- 对象频繁创建和销毁(如子弹、特效粒子)
-- 对象生命周期短暂但使用频繁
-- 需要减少 GC 压力
-
-### Q2: 如何判断是否存在内存泄漏?
-
-**A**: 观察以下指标:
-
-- 内存使用持续增长,不会下降
-- GC 频率增加但内存不释放
-- 事件订阅数量持续增加
-- 对象池中的活跃对象数量异常
-
-使用内存分析工具(如 dotMemory)定位泄漏源。
-
-### Q3: 协程和 async/await 如何选择?
-
-**A**: 选择建议:
-
-- **协程** - 游戏逻辑、动画序列、分帧处理
-- **async/await** - I/O 操作、网络请求、文件读写
-
-协程更适合游戏帧循环,async/await 更适合异步 I/O。
-
-### Q4: 如何优化大量实体的性能?
-
-**A**: 使用 ECS 架构:
-
-- 使用值类型组件减少堆分配
-- 预构建查询避免每帧创建
-- 批量处理实体操作
-- 使用并行处理(如果支持)
-
-### Q5: 什么时候应该进行性能优化?
-
-**A**: 遵循以下原则:
-
-- **先测量,再优化** - 使用性能分析工具找到真正的瓶颈
-- **优先优化热点** - 集中优化占用时间最多的代码
-- **避免过早优化** - 在功能完成后再进行优化
-- **保持可读性** - 不要为了微小的性能提升牺牲代码可读性
-
-### Q6: 如何减少 GC 压力?
-
-**A**: 采取以下措施:
-
-- 使用对象池复用对象
-- 使用值类型(struct)而非引用类型(class)
-- 使用 Span<T> 和 stackalloc 进行栈分配
-- 避免闭包捕获和装箱操作
-- 缓存常用对象和委托
-- 使用 StringBuilder 而非字符串拼接
-
----
-
-## 总结
-
-性能优化是一个持续的过程,需要:
-
-- ✅ **测量优先** - 使用工具定位真正的瓶颈
-- ✅ **合理使用对象池** - 减少 GC 压力
-- ✅ **优化事件系统** - 避免内存泄漏和不必要的处理
-- ✅ **高效使用协程** - 避免过度嵌套和不必要的等待
-- ✅ **智能资源管理** - 异步加载和合理缓存
-- ✅ **ECS 架构优化** - 提高数据局部性和处理效率
-- ✅ **内存优化** - 减少分配,使用栈内存
-- ✅ **持续监控** - 建立性能监控系统
-
-记住,性能优化要在可维护性和性能之间找到平衡,不要为了微小的性能提升而牺牲代码质量。
-
----
-
-**文档版本**: 1.0.0
-**更新日期**: 2026-03-07
+# 性能优化指南
+
+> 全面的性能优化策略和最佳实践,帮助你构建高性能的游戏应用。
+
+## 📋 目录
+
+- [概述](#概述)
+- [核心概念](#核心概念)
+- [对象池优化](#对象池优化)
+- [事件系统优化](#事件系统优化)
+- [协程优化](#协程优化)
+- [资源管理优化](#资源管理优化)
+- [ECS 性能优化](#ecs-性能优化)
+- [内存优化](#内存优化)
+- [最佳实践](#最佳实践)
+- [常见问题](#常见问题)
+
+## 概述
+
+性能优化是游戏开发中的关键环节。良好的性能不仅能提供流畅的用户体验,还能降低设备功耗,延长电池寿命。本指南将介绍 GFramework
+中的性能优化策略和最佳实践。
+
+### 性能优化的重要性
+
+- **用户体验** - 流畅的帧率和快速的响应时间
+- **设备兼容性** - 在低端设备上也能良好运行
+- **资源效率** - 降低内存占用和 CPU 使用率
+- **电池寿命** - 减少不必要的计算和内存分配
+
+## 核心概念
+
+### 1. 性能瓶颈
+
+性能瓶颈是指限制系统整体性能的关键因素:
+
+- **CPU 瓶颈** - 过多的计算、复杂的逻辑
+- **内存瓶颈** - 频繁的 GC、内存泄漏
+- **GPU 瓶颈** - 过多的绘制调用、复杂的着色器
+- **I/O 瓶颈** - 频繁的文件读写、网络请求
+
+### 2. 性能指标
+
+关键的性能指标:
+
+- **帧率 (FPS)** - 每秒渲染的帧数,目标 60 FPS
+- **帧时间** - 每帧的处理时间,目标 <16.67ms
+- **内存占用** - 应用程序使用的内存量
+- **GC 频率** - 垃圾回收的频率和耗时
+- **加载时间** - 场景和资源的加载时间
+
+### 3. 优化策略
+
+性能优化的基本策略:
+
+- **测量优先** - 先测量,再优化
+- **找到瓶颈** - 使用性能分析工具定位问题
+- **渐进优化** - 逐步优化,避免过早优化
+- **权衡取舍** - 在性能和可维护性之间找到平衡
+
+## 对象池优化
+
+对象池是减少 GC 压力的有效手段,通过复用对象避免频繁的内存分配和释放。
+
+### 1. 使用对象池系统
+
+```csharp
+// ✅ 好的做法:使用对象池
+public class BulletPoolSystem : AbstractObjectPoolSystem<string, Bullet>
+{
+ protected override Bullet Create(string key)
+ {
+ // 创建新的子弹对象
+ var bullet = new Bullet();
+ bullet.Initialize(key);
+ return bullet;
+ }
+}
+
+public class Bullet : IPoolableObject
+{
+ public string Type { get; private set; }
+ public Vector2 Position { get; set; }
+ public Vector2 Velocity { get; set; }
+ public bool IsActive { get; private set; }
+
+ public void Initialize(string type)
+ {
+ Type = type;
+ }
+
+ public void OnAcquire()
+ {
+ // 从池中获取时重置状态
+ IsActive = true;
+ Position = Vector2.Zero;
+ Velocity = Vector2.Zero;
+ }
+
+ public void OnRelease()
+ {
+ // 归还到池中时清理状态
+ IsActive = false;
+ }
+
+ public void OnPoolDestroy()
+ {
+ // 对象被销毁时的清理
+ }
+}
+
+// 使用对象池
+public class CombatSystem : AbstractSystem
+{
+ private BulletPoolSystem _bulletPool;
+
+ protected override void OnInit()
+ {
+ _bulletPool = GetSystem<BulletPoolSystem>();
+
+ // 预热对象池
+ _bulletPool.Prewarm("normal_bullet", 50);
+ _bulletPool.Prewarm("fire_bullet", 20);
+ }
+
+ private void FireBullet(string bulletType, Vector2 position, Vector2 direction)
+ {
+ // 从池中获取子弹
+ var bullet = _bulletPool.Acquire(bulletType);
+ bullet.Position = position;
+ bullet.Velocity = direction * 10f;
+
+ // 使用完毕后归还
+ // bullet 会在生命周期结束时自动归还
+ }
+}
+
+// ❌ 避免:频繁创建和销毁对象
+public class CombatSystem : AbstractSystem
+{
+ private void FireBullet(string bulletType, Vector2 position, Vector2 direction)
+ {
+ // 每次都创建新对象,产生大量 GC
+ var bullet = new Bullet();
+ bullet.Type = bulletType;
+ bullet.Position = position;
+ bullet.Velocity = direction * 10f;
+
+ // 使用完毕后直接丢弃,等待 GC 回收
+ }
+}
+```
+
+### 2. StringBuilder 池
+
+GFramework 提供了 `StringBuilderPool` 用于高效的字符串构建:
+
+```csharp
+// ✅ 好的做法:使用 StringBuilderPool
+public string FormatPlayerInfo(Player player)
+{
+ using var sb = StringBuilderPool.GetScoped();
+ sb.Value.Append("Player: ");
+ sb.Value.Append(player.Name);
+ sb.Value.Append(", Level: ");
+ sb.Value.Append(player.Level);
+ sb.Value.Append(", HP: ");
+ sb.Value.Append(player.Health);
+ sb.Value.Append("/");
+ sb.Value.Append(player.MaxHealth);
+ return sb.Value.ToString();
+}
+
+// 或者手动管理
+public string FormatPlayerInfo(Player player)
+{
+ var sb = StringBuilderPool.Rent();
+ try
+ {
+ sb.Append("Player: ").Append(player.Name);
+ sb.Append(", Level: ").Append(player.Level);
+ sb.Append(", HP: ").Append(player.Health).Append("/").Append(player.MaxHealth);
+ return sb.ToString();
+ }
+ finally
+ {
+ StringBuilderPool.Return(sb);
+ }
+}
+
+// ❌ 避免:频繁的字符串拼接
+public string FormatPlayerInfo(Player player)
+{
+ // 每次拼接都会创建新的字符串对象
+ return "Player: " + player.Name +
+ ", Level: " + player.Level +
+ ", HP: " + player.Health + "/" + player.MaxHealth;
+}
+```
+
+### 3. ArrayPool 优化
+
+使用 `ArrayPool` 避免频繁的数组分配:
+
+```csharp
+// ✅ 好的做法:使用 ArrayPool
+public void ProcessEntities(List<Entity> entities)
+{
+ using var scopedArray = ArrayPool<Entity>.Shared.GetScoped(entities.Count);
+ var array = scopedArray.Array;
+
+ // 复制到数组进行处理
+ entities.CopyTo(array, 0);
+
+ // 处理数组
+ for (int i = 0; i < entities.Count; i++)
+ {
+ ProcessEntity(array[i]);
+ }
+
+ // 自动归还到池中
+}
+
+// ❌ 避免:频繁创建数组
+public void ProcessEntities(List<Entity> entities)
+{
+ // 每次都创建新数组
+ var array = entities.ToArray();
+
+ foreach (var entity in array)
+ {
+ ProcessEntity(entity);
+ }
+
+ // 数组等待 GC 回收
+}
+```
+
+### 4. 对象池统计
+
+监控对象池的使用情况:
+
+```csharp
+public class PoolMonitorSystem : AbstractSystem
+{
+ private BulletPoolSystem _bulletPool;
+
+ protected override void OnInit()
+ {
+ _bulletPool = GetSystem<BulletPoolSystem>();
+ }
+
+ public void LogPoolStatistics(string poolKey)
+ {
+ var stats = _bulletPool.GetStatistics(poolKey);
+
+ Logger.Info($"Pool Statistics for '{poolKey}':");
+ Logger.Info($" Available: {stats.AvailableCount}");
+ Logger.Info($" Active: {stats.ActiveCount}");
+ Logger.Info($" Total Created: {stats.TotalCreated}");
+ Logger.Info($" Total Acquired: {stats.TotalAcquired}");
+ Logger.Info($" Total Released: {stats.TotalReleased}");
+ Logger.Info($" Total Destroyed: {stats.TotalDestroyed}");
+
+ // 检查是否需要调整池大小
+ if (stats.TotalDestroyed > stats.TotalCreated * 0.5)
+ {
+ Logger.Warning($"Pool '{poolKey}' has high destruction rate, consider increasing max capacity");
+ }
+ }
+}
+```
+
+## 事件系统优化
+
+事件系统是游戏架构的核心,优化事件处理可以显著提升性能。
+
+### 1. 避免事件订阅泄漏
+
+```csharp
+using GFramework.Core.Abstractions.controller;
+using GFramework.SourceGenerators.Abstractions.rule;
+
+// ✅ 好的做法:正确管理事件订阅
+[ContextAware]
+public partial class PlayerController : Node, IController
+{
+ private IUnRegisterList _unRegisterList = new UnRegisterList();
+ private PlayerModel _playerModel;
+
+ public void Initialize()
+ {
+ _playerModel = Context.GetModel<PlayerModel>();
+
+ // 使用 UnRegisterList 管理订阅
+ Context.RegisterEvent<PlayerDamagedEvent>(OnPlayerDamaged)
+ .AddTo(_unRegisterList);
+
+ _playerModel.Health.Register(OnHealthChanged)
+ .AddTo(_unRegisterList);
+ }
+
+ public void Cleanup()
+ {
+ // 统一取消所有订阅
+ _unRegisterList.UnRegisterAll();
+ }
+
+ private void OnPlayerDamaged(PlayerDamagedEvent e) { }
+ private void OnHealthChanged(int health) { }
+}
+
+// ❌ 避免:忘记取消订阅
+[ContextAware]
+public partial class PlayerController : Node, IController
+{
+ public void Initialize()
+ {
+ // 订阅事件但从不取消订阅
+ Context.RegisterEvent<PlayerDamagedEvent>(OnPlayerDamaged);
+
+ var playerModel = Context.GetModel<PlayerModel>();
+ playerModel.Health.Register(OnHealthChanged);
+
+ // 当对象被销毁时,这些订阅仍然存在,导致内存泄漏
+ }
+}
+```
+
+### 2. 使用结构体事件
+
+使用值类型事件避免堆分配:
+
+```csharp
+// ✅ 好的做法:使用结构体事件
+public struct PlayerMovedEvent
+{
+ public string PlayerId { get; init; }
+ public Vector2 OldPosition { get; init; }
+ public Vector2 NewPosition { get; init; }
+ public float DeltaTime { get; init; }
+}
+
+public class MovementSystem : AbstractSystem
+{
+ private void NotifyPlayerMoved(string playerId, Vector2 oldPos, Vector2 newPos, float deltaTime)
+ {
+ // 结构体在栈上分配,无 GC 压力
+ SendEvent(new PlayerMovedEvent
+ {
+ PlayerId = playerId,
+ OldPosition = oldPos,
+ NewPosition = newPos,
+ DeltaTime = deltaTime
+ });
+ }
+}
+
+// ❌ 避免:使用类事件
+public class PlayerMovedEvent
+{
+ public string PlayerId { get; set; }
+ public Vector2 OldPosition { get; set; }
+ public Vector2 NewPosition { get; set; }
+ public float DeltaTime { get; set; }
+}
+
+// 每次发送事件都会在堆上分配对象
+```
+
+### 3. 批量事件处理
+
+对于高频事件,考虑批量处理:
+
+```csharp
+// ✅ 好的做法:批量处理事件
+public class DamageSystem : AbstractSystem
+{
+ private readonly List<DamageInfo> _pendingDamages = new();
+ private float _batchInterval = 0.1f;
+ private float _timeSinceLastBatch = 0f;
+
+ public void Update(float deltaTime)
+ {
+ _timeSinceLastBatch += deltaTime;
+
+ if (_timeSinceLastBatch >= _batchInterval)
+ {
+ ProcessDamageBatch();
+ _timeSinceLastBatch = 0f;
+ }
+ }
+
+ public void QueueDamage(string entityId, int damage, DamageType type)
+ {
+ _pendingDamages.Add(new DamageInfo
+ {
+ EntityId = entityId,
+ Damage = damage,
+ Type = type
+ });
+ }
+
+ private void ProcessDamageBatch()
+ {
+ if (_pendingDamages.Count == 0)
+ return;
+
+ // 批量处理所有伤害
+ foreach (var damageInfo in _pendingDamages)
+ {
+ ApplyDamage(damageInfo);
+ }
+
+ // 发送单个批量事件
+ SendEvent(new DamageBatchProcessedEvent
+ {
+ DamageCount = _pendingDamages.Count,
+ TotalDamage = _pendingDamages.Sum(d => d.Damage)
+ });
+
+ _pendingDamages.Clear();
+ }
+}
+
+// ❌ 避免:每次都立即处理
+public class DamageSystem : AbstractSystem
+{
+ public void ApplyDamage(string entityId, int damage, DamageType type)
+ {
+ // 每次伤害都立即处理并发送事件
+ ProcessDamage(entityId, damage, type);
+ SendEvent(new DamageAppliedEvent { EntityId = entityId, Damage = damage });
+ }
+}
+```
+
+### 4. 事件优先级优化
+
+合理使用事件优先级避免不必要的处理:
+
+```csharp
+// ✅ 好的做法:使用优先级控制事件传播
+public class InputSystem : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ // UI 输入处理器优先级最高
+ this.RegisterEvent<InputEvent>(OnUIInput, priority: 100);
+ }
+
+ private void OnUIInput(InputEvent e)
+ {
+ if (IsUIHandlingInput())
+ {
+ // 停止事件传播,避免游戏逻辑处理
+ e.StopPropagation();
+ }
+ }
+}
+
+public class GameplayInputSystem : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ // 游戏逻辑输入处理器优先级较低
+ this.RegisterEvent<InputEvent>(OnGameplayInput, priority: 50);
+ }
+
+ private void OnGameplayInput(InputEvent e)
+ {
+ // 如果 UI 已经处理了输入,这里不会执行
+ if (!e.IsPropagationStopped)
+ {
+ ProcessGameplayInput(e);
+ }
+ }
+}
+```
+
+## 协程优化
+
+协程是处理异步逻辑的强大工具,但不当使用会影响性能。
+
+### 1. 避免过度嵌套
+
+```csharp
+// ✅ 好的做法:扁平化协程结构
+public IEnumerator<IYieldInstruction> LoadGameSequence()
+{
+ // 显示加载界面
+ yield return ShowLoadingScreen();
+
+ // 加载配置
+ yield return LoadConfiguration();
+
+ // 加载资源
+ yield return LoadResources();
+
+ // 初始化系统
+ yield return InitializeSystems();
+
+ // 隐藏加载界面
+ yield return HideLoadingScreen();
+}
+
+private IEnumerator<IYieldInstruction> LoadConfiguration()
+{
+ var config = await ConfigManager.LoadAsync();
+ ApplyConfiguration(config);
+ yield break;
+}
+
+// ❌ 避免:深度嵌套
+public IEnumerator<IYieldInstruction> LoadGameSequence()
+{
+ yield return ShowLoadingScreen().Then(() =>
+ {
+ return LoadConfiguration().Then(() =>
+ {
+ return LoadResources().Then(() =>
+ {
+ return InitializeSystems().Then(() =>
+ {
+ return HideLoadingScreen();
+ });
+ });
+ });
+ });
+}
+```
+
+### 2. 协程池化
+
+对于频繁启动的协程,考虑复用:
+
+```csharp
+// ✅ 好的做法:复用协程逻辑
+public class EffectSystem : AbstractSystem
+{
+ private readonly Dictionary<string, IEnumerator<IYieldInstruction>> _effectCoroutines = new();
+
+ public CoroutineHandle PlayEffect(string effectId, Vector2 position)
+ {
+ // 复用协程逻辑
+ return this.StartCoroutine(EffectCoroutine(effectId, position));
+ }
+
+ private IEnumerator<IYieldInstruction> EffectCoroutine(string effectId, Vector2 position)
+ {
+ var effect = CreateEffect(effectId, position);
+
+ // 播放效果
+ yield return new Delay(effect.Duration);
+
+ // 清理效果
+ DestroyEffect(effect);
+ }
+}
+```
+
+### 3. 合理使用 WaitForFrames
+
+```csharp
+// ✅ 好的做法:使用 WaitForFrames 分帧处理
+public IEnumerator<IYieldInstruction> ProcessLargeDataSet(List<Data> dataSet)
+{
+ const int batchSize = 100;
+
+ for (int i = 0; i < dataSet.Count; i += batchSize)
+ {
+ int end = Math.Min(i + batchSize, dataSet.Count);
+
+ // 处理一批数据
+ for (int j = i; j < end; j++)
+ {
+ ProcessData(dataSet[j]);
+ }
+
+ // 等待一帧,避免卡顿
+ yield return new WaitOneFrame();
+ }
+}
+
+// ❌ 避免:一次性处理大量数据
+public void ProcessLargeDataSet(List<Data> dataSet)
+{
+ // 一次性处理所有数据,可能导致帧率下降
+ foreach (var data in dataSet)
+ {
+ ProcessData(data);
+ }
+}
+```
+
+### 4. 协程取消优化
+
+```csharp
+// ✅ 好的做法:及时取消不需要的协程
+public class AnimationController : AbstractSystem
+{
+ private CoroutineHandle _currentAnimation;
+
+ public void PlayAnimation(string animationName)
+ {
+ // 取消当前动画
+ if (_currentAnimation.IsValid)
+ {
+ this.StopCoroutine(_currentAnimation);
+ }
+
+ // 播放新动画
+ _currentAnimation = this.StartCoroutine(AnimationCoroutine(animationName));
+ }
+
+ private IEnumerator<IYieldInstruction> AnimationCoroutine(string animationName)
+ {
+ var animation = GetAnimation(animationName);
+
+ while (!animation.IsComplete)
+ {
+ animation.Update(Time.DeltaTime);
+ yield return new WaitOneFrame();
+ }
+ }
+}
+```
+
+## 资源管理优化
+
+高效的资源管理可以显著减少加载时间和内存占用。
+
+### 1. 资源预加载
+
+```csharp
+// ✅ 好的做法:预加载常用资源
+public class ResourcePreloader : AbstractSystem
+{
+ private IResourceManager _resourceManager;
+
+ protected override void OnInit()
+ {
+ _resourceManager = GetUtility<IResourceManager>();
+ }
+
+ public async Task PreloadCommonResources()
+ {
+ // 预加载 UI 资源
+ await _resourceManager.PreloadAsync<Texture>("ui/button_normal");
+ await _resourceManager.PreloadAsync<Texture>("ui/button_pressed");
+ await _resourceManager.PreloadAsync<Texture>("ui/button_hover");
+
+ // 预加载音效
+ await _resourceManager.PreloadAsync<AudioClip>("sfx/button_click");
+ await _resourceManager.PreloadAsync<AudioClip>("sfx/button_hover");
+
+ // 预加载特效
+ await _resourceManager.PreloadAsync<ParticleSystem>("effects/hit_effect");
+ await _resourceManager.PreloadAsync<ParticleSystem>("effects/explosion");
+ }
+}
+```
+
+### 2. 异步加载
+
+```csharp
+// ✅ 好的做法:使用异步加载避免阻塞
+public class SceneLoader : AbstractSystem
+{
+ private IResourceManager _resourceManager;
+
+ public async Task LoadSceneAsync(string sceneName)
+ {
+ // 显示加载进度
+ var progress = 0f;
+ UpdateLoadingProgress(progress);
+
+ // 异步加载场景资源
+ var sceneData = await _resourceManager.LoadAsync<SceneData>($"scenes/{sceneName}");
+ progress += 0.3f;
+ UpdateLoadingProgress(progress);
+
+ // 异步加载场景依赖的资源
+ await LoadSceneDependencies(sceneData);
+ progress += 0.5f;
+ UpdateLoadingProgress(progress);
+
+ // 初始化场景
+ await InitializeScene(sceneData);
+ progress = 1f;
+ UpdateLoadingProgress(progress);
+ }
+
+ private async Task LoadSceneDependencies(SceneData sceneData)
+ {
+ var tasks = new List<Task>();
+
+ foreach (var dependency in sceneData.Dependencies)
+ {
+ tasks.Add(_resourceManager.LoadAsync<object>(dependency));
+ }
+
+ await Task.WhenAll(tasks);
+ }
+}
+
+// ❌ 避免:同步加载阻塞主线程
+public class SceneLoader : AbstractSystem
+{
+ public void LoadScene(string sceneName)
+ {
+ // 同步加载会阻塞主线程,导致卡顿
+ var sceneData = _resourceManager.Load<SceneData>($"scenes/{sceneName}");
+ LoadSceneDependencies(sceneData);
+ InitializeScene(sceneData);
+ }
+}
+```
+
+### 3. 资源引用计数
+
+```csharp
+// ✅ 好的做法:使用资源句柄管理引用
+public class EntityRenderer : AbstractSystem
+{
+ private readonly Dictionary<string, IResourceHandle<Texture>> _textureHandles = new();
+
+ public void LoadTexture(string entityId, string texturePath)
+ {
+ // 获取资源句柄
+ var handle = _resourceManager.GetHandle<Texture>(texturePath);
+ if (handle != null)
+ {
+ _textureHandles[entityId] = handle;
+ }
+ }
+
+ public void UnloadTexture(string entityId)
+ {
+ if (_textureHandles.TryGetValue(entityId, out var handle))
+ {
+ // 释放句柄,自动管理引用计数
+ handle.Dispose();
+ _textureHandles.Remove(entityId);
+ }
+ }
+
+ protected override void OnDestroy()
+ {
+ // 清理所有句柄
+ foreach (var handle in _textureHandles.Values)
+ {
+ handle.Dispose();
+ }
+ _textureHandles.Clear();
+ }
+}
+```
+
+### 4. 资源缓存策略
+
+```csharp
+// ✅ 好的做法:使用合适的释放策略
+public class GameResourceManager : AbstractSystem
+{
+ private IResourceManager _resourceManager;
+
+ protected override void OnInit()
+ {
+ _resourceManager = GetUtility<IResourceManager>();
+
+ // 设置自动释放策略
+ _resourceManager.SetReleaseStrategy(new AutoReleaseStrategy());
+ }
+
+ public void OnSceneChanged()
+ {
+ // 场景切换时卸载未使用的资源
+ UnloadUnusedResources();
+ }
+
+ private void UnloadUnusedResources()
+ {
+ var loadedPaths = _resourceManager.GetLoadedResourcePaths().ToList();
+
+ foreach (var path in loadedPaths)
+ {
+ // 检查资源是否仍在使用
+ if (!IsResourceInUse(path))
+ {
+ _resourceManager.Unload(path);
+ }
+ }
+ }
+
+ private bool IsResourceInUse(string path)
+ {
+ // 检查资源引用计数
+ return false; // 实现具体逻辑
+ }
+}
+```
+
+## ECS 性能优化
+
+Entity Component System (ECS) 是高性能游戏架构的关键。
+
+### 1. 组件设计优化
+
+```csharp
+// ✅ 好的做法:使用值类型组件
+public struct Position
+{
+ public float X;
+ public float Y;
+ public float Z;
+}
+
+public struct Velocity
+{
+ public float X;
+ public float Y;
+ public float Z;
+}
+
+public struct Health
+{
+ public int Current;
+ public int Max;
+}
+
+// ❌ 避免:使用引用类型组件
+public class Position
+{
+ public float X { get; set; }
+ public float Y { get; set; }
+ public float Z { get; set; }
+}
+```
+
+### 2. 查询优化
+
+```csharp
+// ✅ 好的做法:使用高效的查询
+public class MovementSystem : ArchSystemAdapter
+{
+ private QueryDescription _movementQuery;
+
+ public override void Initialize()
+ {
+ // 预先构建查询
+ _movementQuery = new QueryDescription()
+ .WithAll<Position, Velocity>()
+ .WithNone<Frozen>();
+ }
+
+ public override void Update(float deltaTime)
+ {
+ // 使用预构建的查询
+ World.Query(in _movementQuery, (ref Position pos, ref Velocity vel) =>
+ {
+ pos.X += vel.X * deltaTime;
+ pos.Y += vel.Y * deltaTime;
+ pos.Z += vel.Z * deltaTime;
+ });
+ }
+}
+
+// ❌ 避免:每帧构建查询
+public class MovementSystem : ArchSystemAdapter
+{
+ public override void Update(float deltaTime)
+ {
+ // 每帧都构建新查询,性能差
+ var query = new QueryDescription()
+ .WithAll<Position, Velocity>()
+ .WithNone<Frozen>();
+
+ World.Query(in query, (ref Position pos, ref Velocity vel) =>
+ {
+ pos.X += vel.X * deltaTime;
+ pos.Y += vel.Y * deltaTime;
+ pos.Z += vel.Z * deltaTime;
+ });
+ }
+}
+```
+
+### 3. 批量处理
+
+```csharp
+// ✅ 好的做法:批量处理实体
+public class DamageSystem : ArchSystemAdapter
+{
+ private readonly List<(EntityReference entity, int damage)> _pendingDamages = new();
+
+ public void QueueDamage(EntityReference entity, int damage)
+ {
+ _pendingDamages.Add((entity, damage));
+ }
+
+ public override void Update(float deltaTime)
+ {
+ if (_pendingDamages.Count == 0)
+ return;
+
+ // 批量应用伤害
+ foreach (var (entity, damage) in _pendingDamages)
+ {
+ if (World.IsAlive(entity))
+ {
+ ref var health = ref World.Get<Health>(entity);
+ health.Current = Math.Max(0, health.Current - damage);
+
+ if (health.Current == 0)
+ {
+ World.Destroy(entity);
+ }
+ }
+ }
+
+ _pendingDamages.Clear();
+ }
+}
+```
+
+### 4. 避免装箱
+
+```csharp
+// ✅ 好的做法:避免装箱操作
+public struct EntityId : IEquatable<EntityId>
+{
+ public int Value;
+
+ public bool Equals(EntityId other) => Value == other.Value;
+ public override bool Equals(object obj) => obj is EntityId other && Equals(other);
+ public override int GetHashCode() => Value;
+}
+
+// 使用泛型避免装箱
+public class EntityCache<T> where T : struct
+{
+ private readonly Dictionary<EntityId, T> _cache = new();
+
+ public void Add(EntityId id, T data)
+ {
+ _cache[id] = data; // 无装箱
+ }
+
+ public bool TryGet(EntityId id, out T data)
+ {
+ return _cache.TryGetValue(id, out data); // 无装箱
+ }
+}
+
+// ❌ 避免:导致装箱的操作
+public class EntityCache
+{
+ private readonly Dictionary<int, object> _cache = new();
+
+ public void Add(int id, object data)
+ {
+ _cache[id] = data; // 值类型会装箱
+ }
+}
+```
+
+## 内存优化
+
+减少内存分配和 GC 压力是性能优化的重要方面。
+
+### 1. 使用 Span<T>
+
+```csharp
+// ✅ 好的做法:使用 Span 避免分配
+public void ProcessData(ReadOnlySpan<byte> data)
+{
+ // 直接在栈上处理,无堆分配
+ Span<int> results = stackalloc int[data.Length];
+
+ for (int i = 0; i < data.Length; i++)
+ {
+ results[i] = ProcessByte(data[i]);
+ }
+
+ // 使用结果
+ UseResults(results);
+}
+
+// 解析字符串避免分配
+public bool TryParseValue(ReadOnlySpan<char> input, out int result)
+{
+ return int.TryParse(input, out result);
+}
+
+// ❌ 避免:不必要的数组分配
+public void ProcessData(byte[] data)
+{
+ // 创建新数组,产生 GC
+ var results = new int[data.Length];
+
+ for (int i = 0; i < data.Length; i++)
+ {
+ results[i] = ProcessByte(data[i]);
+ }
+
+ UseResults(results);
+}
+```
+
+### 2. 结构体优化
+
+```csharp
+// ✅ 好的做法:使用 readonly struct
+public readonly struct Vector2D
+{
+ public readonly float X;
+ public readonly float Y;
+
+ public Vector2D(float x, float y)
+ {
+ X = x;
+ Y = y;
+ }
+
+ public float Length() => MathF.Sqrt(X * X + Y * Y);
+
+ public Vector2D Normalized()
+ {
+ var length = Length();
+ return length > 0 ? new Vector2D(X / length, Y / length) : this;
+ }
+}
+
+// ❌ 避免:可变结构体
+public struct Vector2D
+{
+ public float X { get; set; }
+ public float Y { get; set; }
+
+ // 可变结构体可能导致意外的复制
+}
+```
+
+### 3. 避免闭包分配
+
+```csharp
+// ✅ 好的做法:避免闭包捕获
+public class EventProcessor : AbstractSystem
+{
+ private readonly Action<PlayerEvent> _cachedHandler;
+
+ public EventProcessor()
+ {
+ // 缓存委托,避免每次分配
+ _cachedHandler = HandlePlayerEvent;
+ }
+
+ protected override void OnInit()
+ {
+ this.RegisterEvent(_cachedHandler);
+ }
+
+ private void HandlePlayerEvent(PlayerEvent e)
+ {
+ ProcessEvent(e);
+ }
+}
+
+// ❌ 避免:每次都创建新的闭包
+public class EventProcessor : AbstractSystem
+{
+ protected override void OnInit()
+ {
+ // 每次都创建新的委托和闭包
+ this.RegisterEvent<PlayerEvent>(e =>
+ {
+ ProcessEvent(e);
+ });
+ }
+}
+```
+
+### 4. 字符串优化
+
+```csharp
+// ✅ 好的做法:减少字符串分配
+public class Logger
+{
+ private readonly StringBuilder _sb = new();
+
+ public void LogFormat(string format, params object[] args)
+ {
+ _sb.Clear();
+ _sb.AppendFormat(format, args);
+ Log(_sb.ToString());
+ }
+
+ // 使用字符串插值的优化版本
+ public void LogInterpolated(ref DefaultInterpolatedStringHandler handler)
+ {
+ Log(handler.ToStringAndClear());
+ }
+}
+
+// 使用 string.Create 避免中间分配
+public string CreateEntityName(int id, string type)
+{
+ return string.Create(type.Length + 10, (id, type), (span, state) =>
+ {
+ state.type.AsSpan().CopyTo(span);
+ span = span.Slice(state.type.Length);
+ span[0] = '_';
+ state.id.TryFormat(span.Slice(1), out _);
+ });
+}
+
+// ❌ 避免:频繁的字符串拼接
+public string CreateEntityName(int id, string type)
+{
+ return type + "_" + id.ToString(); // 创建多个临时字符串
+}
+```
+
+## 最佳实践
+
+### 1. 性能测试
+
+```csharp
+// ✅ 使用性能测试验证优化效果
+[TestFixture]
+public class PerformanceTests
+{
+ [Test]
+ [Performance]
+ public void ObjectPool_Performance_Test()
+ {
+ var pool = new BulletPoolSystem();
+ pool.Prewarm("bullet", 1000);
+
+ Measure.Method(() =>
+ {
+ var bullet = pool.Acquire("bullet");
+ pool.Release("bullet", bullet);
+ })
+ .WarmupCount(10)
+ .MeasurementCount(100)
+ .Run();
+ }
+
+ [Test]
+ public void CompareAllocationMethods()
+ {
+ // 测试对象池
+ var poolTime = MeasureTime(() =>
+ {
+ var pool = ArrayPool<int>.Shared;
+ var array = pool.Rent(1000);
+ pool.Return(array);
+ });
+
+ // 测试直接分配
+ var allocTime = MeasureTime(() =>
+ {
+ var array = new int[1000];
+ });
+
+ Assert.Less(poolTime, allocTime, "Object pool should be faster");
+ }
+
+ private long MeasureTime(Action action)
+ {
+ var sw = Stopwatch.StartNew();
+ for (int i = 0; i < 10000; i++)
+ {
+ action();
+ }
+ sw.Stop();
+ return sw.ElapsedMilliseconds;
+ }
+}
+```
+
+### 2. 性能监控
+
+```csharp
+// ✅ 实现性能监控系统
+public class PerformanceMonitor : AbstractSystem
+{
+ private readonly Dictionary<string, PerformanceMetric> _metrics = new();
+ private float _updateInterval = 1.0f;
+ private float _timeSinceUpdate = 0f;
+
+ public void Update(float deltaTime)
+ {
+ _timeSinceUpdate += deltaTime;
+
+ if (_timeSinceUpdate >= _updateInterval)
+ {
+ UpdateMetrics();
+ _timeSinceUpdate = 0f;
+ }
+ }
+
+ public void RecordMetric(string name, float value)
+ {
+ if (!_metrics.TryGetValue(name, out var metric))
+ {
+ metric = new PerformanceMetric(name);
+ _metrics[name] = metric;
+ }
+
+ metric.AddSample(value);
+ }
+
+ private void UpdateMetrics()
+ {
+ foreach (var metric in _metrics.Values)
+ {
+ Logger.Info($"{metric.Name}: Avg={metric.Average:F2}ms, " +
+ $"Min={metric.Min:F2}ms, Max={metric.Max:F2}ms");
+ metric.Reset();
+ }
+ }
+}
+
+public class PerformanceMetric
+{
+ public string Name { get; }
+ public float Average => _count > 0 ? _sum / _count : 0;
+ public float Min { get; private set; } = float.MaxValue;
+ public float Max { get; private set; } = float.MinValue;
+
+ private float _sum;
+ private int _count;
+
+ public PerformanceMetric(string name)
+ {
+ Name = name;
+ }
+
+ public void AddSample(float value)
+ {
+ _sum += value;
+ _count++;
+ Min = Math.Min(Min, value);
+ Max = Math.Max(Max, value);
+ }
+
+ public void Reset()
+ {
+ _sum = 0;
+ _count = 0;
+ Min = float.MaxValue;
+ Max = float.MinValue;
+ }
+}
+```
+
+### 3. 性能分析工具
+
+使用性能分析工具定位瓶颈:
+
+- **Unity Profiler** - Unity 内置的性能分析工具
+- **Godot Profiler** - Godot 的性能监控工具
+- **dotTrace** - JetBrains 的 .NET 性能分析器
+- **PerfView** - Microsoft 的性能分析工具
+
+### 4. 性能优化清单
+
+在优化性能时,遵循以下清单:
+
+- [ ] 使用对象池减少 GC 压力
+- [ ] 正确管理事件订阅,避免内存泄漏
+- [ ] 使用结构体事件避免堆分配
+- [ ] 合理使用协程,避免过度嵌套
+- [ ] 异步加载资源,避免阻塞主线程
+- [ ] 使用 ECS 架构提高数据局部性
+- [ ] 使用 Span<T> 和 stackalloc 减少分配
+- [ ] 避免装箱操作
+- [ ] 缓存常用的委托和对象
+- [ ] 批量处理高频操作
+- [ ] 定期进行性能测试和监控
+
+## 常见问题
+
+### Q1: 什么时候应该使用对象池?
+
+**A**: 当满足以下条件时考虑使用对象池:
+
+- 对象创建成本高(如包含复杂初始化逻辑)
+- 对象频繁创建和销毁(如子弹、特效粒子)
+- 对象生命周期短暂但使用频繁
+- 需要减少 GC 压力
+
+### Q2: 如何判断是否存在内存泄漏?
+
+**A**: 观察以下指标:
+
+- 内存使用持续增长,不会下降
+- GC 频率增加但内存不释放
+- 事件订阅数量持续增加
+- 对象池中的活跃对象数量异常
+
+使用内存分析工具(如 dotMemory)定位泄漏源。
+
+### Q3: 协程和 async/await 如何选择?
+
+**A**: 选择建议:
+
+- **协程** - 游戏逻辑、动画序列、分帧处理
+- **async/await** - I/O 操作、网络请求、文件读写
+
+协程更适合游戏帧循环,async/await 更适合异步 I/O。
+
+### Q4: 如何优化大量实体的性能?
+
+**A**: 使用 ECS 架构:
+
+- 使用值类型组件减少堆分配
+- 预构建查询避免每帧创建
+- 批量处理实体操作
+- 使用并行处理(如果支持)
+
+### Q5: 什么时候应该进行性能优化?
+
+**A**: 遵循以下原则:
+
+- **先测量,再优化** - 使用性能分析工具找到真正的瓶颈
+- **优先优化热点** - 集中优化占用时间最多的代码
+- **避免过早优化** - 在功能完成后再进行优化
+- **保持可读性** - 不要为了微小的性能提升牺牲代码可读性
+
+### Q6: 如何减少 GC 压力?
+
+**A**: 采取以下措施:
+
+- 使用对象池复用对象
+- 使用值类型(struct)而非引用类型(class)
+- 使用 Span<T> 和 stackalloc 进行栈分配
+- 避免闭包捕获和装箱操作
+- 缓存常用对象和委托
+- 使用 StringBuilder 而非字符串拼接
+
+---
+
+## 总结
+
+性能优化是一个持续的过程,需要:
+
+- ✅ **测量优先** - 使用工具定位真正的瓶颈
+- ✅ **合理使用对象池** - 减少 GC 压力
+- ✅ **优化事件系统** - 避免内存泄漏和不必要的处理
+- ✅ **高效使用协程** - 避免过度嵌套和不必要的等待
+- ✅ **智能资源管理** - 异步加载和合理缓存
+- ✅ **ECS 架构优化** - 提高数据局部性和处理效率
+- ✅ **内存优化** - 减少分配,使用栈内存
+- ✅ **持续监控** - 建立性能监控系统
+
+记住,性能优化要在可维护性和性能之间找到平衡,不要为了微小的性能提升而牺牲代码质量。
+
+---
+
+**文档版本**: 1.0.0
+**更新日期**: 2026-03-07
diff --git a/docs/zh-CN/core/architecture.md b/docs/zh-CN/core/architecture.md
index 76592bf..603f744 100644
--- a/docs/zh-CN/core/architecture.md
+++ b/docs/zh-CN/core/architecture.md
@@ -1,606 +1,608 @@
-# Architecture 包使用说明
-
-## 概述
-
-Architecture 包是整个框架的核心,提供了基于分层架构模式的应用程序架构基础。它实现了依赖注入(IoC)
-容器、组件生命周期管理,以及命令、查询、事件的统一调度机制。
-
-**注意**:本框架的 Core 模块与 Godot 解耦,Godot 相关集成在 GFramework.Godot 包中实现。
-
-## 核心接口
-
-### IArchitecture
-
-架构接口,定义了框架的核心功能契约。
-
-**主要职责:**
-
-- **组件注册**:注册 System、Model、Utility
-- **组件获取**:从容器中获取已注册的组件
-- **命令处理**:发送并执行命令
-- **查询处理**:发送并执行查询
-- **事件管理**:发送、注册、注销事件
-- **模块管理**:安装和管理架构模块
-- **生命周期管理**:管理架构的初始化、运行和销毁阶段
-
-**核心方法:**
-```csharp
-// 组件注册
-void RegisterSystem(TSystem system) where TSystem : ISystem;
-void RegisterModel(TModel model) where TModel : IModel;
-void RegisterUtility(TUtility utility) where TUtility : IUtility;
-
-// 组件获取(通过容器)
-T GetModel() where T : class, IModel;
-T GetSystem() where T : class, ISystem;
-T GetUtility() where T : class, IUtility;
-
-// 命令处理
-void SendCommand(ICommand command);
-TResult SendCommand(ICommand command);
-
-// 查询处理
-TResult SendQuery(IQuery query);
-
-// 事件管理
-void SendEvent() where T : new();
-void SendEvent(T e);
-IUnRegister RegisterEvent(Action onEvent);
-void UnRegisterEvent(Action onEvent);
-```
-
-### IArchitecturePhaseAware
-
-架构阶段感知接口,允许组件监听架构阶段变化。
-
-**核心方法:**
-```csharp
-void OnArchitecturePhase(ArchitecturePhase phase);
-```
-
-### IArchitectureModule
-
-架构模块接口,支持模块化架构扩展。
-
-**核心方法:**
-```csharp
-void Install(IArchitecture architecture);
-```
-
-### IAsyncInitializable
-
-异步初始化接口,支持组件异步初始化。
-
-**核心方法:**
-```csharp
-Task InitializeAsync();
-```
-
-## 核心类
-
-### Architecture 架构基类
-
-架构基类,实现了 `IArchitecture` 接口,提供完整的架构功能实现。
-
-**构造函数参数:**
-```csharp
-public abstract class Architecture(
- IArchitectureConfiguration? configuration = null,
- IEnvironment? environment = null,
- IArchitectureServices? services = null,
- IArchitectureContext? context = null
-)
-```
-
-**特性:**
-
-- **阶段式生命周期管理**
- :支持多个架构阶段(BeforeUtilityInit、AfterUtilityInit、BeforeModelInit、AfterModelInit、BeforeSystemInit、AfterSystemInit、Ready、FailedInitialization、Destroying、Destroyed)
-- **模块安装系统**:支持通过 `InstallModule` 扩展架构功能
-- **异步初始化**:支持同步和异步两种初始化方式
-- **IoC 容器集成**:内置依赖注入容器
-- **事件系统集成**:集成类型化事件系统
-- **与平台无关**:Core 模块不依赖 Godot,可以在任何 .NET 环境中使用
-- **严格的阶段验证**:可配置的阶段转换验证机制
-- **组件生命周期管理**:自动管理组件的初始化和销毁
-
-**架构阶段:**
-```csharp
-public enum ArchitecturePhase
-{
- None = 0, // 初始阶段
- BeforeUtilityInit = 1, // 工具初始化前
- AfterUtilityInit = 2, // 工具初始化后
- BeforeModelInit = 3, // 模型初始化前
- AfterModelInit = 4, // 模型初始化后
- BeforeSystemInit = 5, // 系统初始化前
- AfterSystemInit = 6, // 系统初始化后
- Ready = 7, // 就绪状态
- FailedInitialization = 8, // 初始化失败
- Destroying = 9, // 正在销毁
- Destroyed = 10 // 已销毁
-}
-```
-
-**初始化流程:**
-
-1. 创建架构实例(传入配置或使用默认配置)
-2. 初始化基础上下文和日志系统
-3. 调用用户自定义的 `Init()` 方法
-4. 按顺序初始化组件:
- - 工具初始化(BeforeUtilityInit → AfterUtilityInit)
- - 模型初始化(BeforeModelInit → AfterModelInit)
- - 系统初始化(BeforeSystemInit → AfterSystemInit)
-5. 冻结 IOC 容器
-6. 进入 Ready 阶段
-
-**销毁流程:**
-
-1. 进入 Destroying 阶段
-2. 按注册逆序销毁所有实现了 `IDisposable` 的组件
-3. 进入 Destroyed 阶段
-4. 清理所有资源
-
-**使用示例:**
-
-```csharp
-// 1. 定义你的架构(继承 Architecture 基类)
-public class GameArchitecture : Architecture
-{
- protected override void Init()
- {
- // 注册 Model
- RegisterModel(new PlayerModel());
- RegisterModel(new InventoryModel());
-
- // 注册 System
- RegisterSystem(new GameplaySystem());
- RegisterSystem(new SaveSystem());
-
- // 注册 Utility
- RegisterUtility(new StorageUtility());
- RegisterUtility(new TimeUtility());
- }
-}
-
-// 2. 创建并初始化架构
-var architecture = new GameArchitecture();
-architecture.Initialize();
-
-// 或者异步初始化
-// var architecture = new GameArchitecture();
-// await architecture.InitializeAsync();
-
-// 3. 等待架构就绪
-await architecture.WaitUntilReadyAsync();
-
-// 4. 通过依赖注入使用架构
-// 在 Controller 或其他组件中获取架构实例
-public class GameController : IController
-{
- public IArchitecture GetArchitecture() => GameArchitecture.Interface;
-
- public void Start()
- {
- // 获取 Model
- var playerModel = this.GetModel();
-
- // 发送命令
- this.SendCommand(new StartGameCommand());
-
- // 发送查询
- var score = this.SendQuery(new GetScoreQuery());
-
- // 注册事件
- this.RegisterEvent(OnPlayerDied);
- }
-
- private void OnPlayerDied(PlayerDiedEvent e)
- {
- // 处理玩家死亡事件
- }
-}
-```
-
-**核心方法与属性:**
-
-#### 初始化方法
-
-**Initialize()**
-
-同步初始化方法,阻塞当前线程直到初始化完成。
-```csharp
-public void Initialize()
-```
-
-**特点:**
-
-- 阻塞式初始化
-- 适用于简单场景或控制台应用
-- 初始化失败时抛出异常并进入 `FailedInitialization` 阶段
-
-使用示例:
-```csharp
-var architecture = new GameArchitecture();
-architecture.Initialize(); // 阻塞等待初始化完成
-```
-
-异常处理:如果初始化过程中发生异常,架构会进入 `FailedInitialization` 阶段。
-
-**InitializeAsync()**
-
-异步初始化方法,返回 Task 以便调用者可以等待初始化完成。
-```csharp
-public async Task InitializeAsync()
-```
-
-**特点:**
-
-- 非阻塞式初始化
-- 支持异步组件初始化
-- 适用于需要异步加载资源的场景
-- 初始化失败时抛出异常并进入 `FailedInitialization` 阶段
-
-使用示例:
-```csharp
-var architecture = new GameArchitecture();
-await architecture.InitializeAsync(); // 异步等待初始化完成
-```
-
-优势:
-- 支持异步初始化 Model 和 System
-- 可以利用异步 I/O 操作(如异步加载数据)
-- 提高初始化性能
-- 不会阻塞主线程
-
-#### 模块管理
-
-**InstallModule(IArchitectureModule module)**
-
-安装架构模块,用于扩展架构功能。
-```csharp
-public IArchitectureModule InstallModule(IArchitectureModule module)
-```
-
-**返回值:** 返回安装的模块实例
-
-**特点:**
-
-- 模块安装时会自动注册生命周期钩子
-- 模块可以注册额外的组件到架构中
-- 只能在架构进入 Ready 阶段之前安装模块
-
-参数:
-
-- `module`:要安装的模块实例
-
-使用示例:
-
-```csharp
-// 定义模块
-public class NetworkModule : IArchitectureModule
-{
- public void Install(IArchitecture architecture)
- {
- // 注册网络相关的 System 和 Utility
- architecture.RegisterSystem(new NetworkSystem());
- architecture.RegisterUtility(new HttpClientUtility());
- }
-}
-
-// 安装模块
-var architecture = new GameArchitecture();
-var installedModule = architecture.InstallModule(new NetworkModule());
-```
-
-#### 生命周期钩子
-
-**RegisterLifecycleHook(IArchitectureLifecycle hook)**
-
-注册生命周期钩子,用于在架构阶段变化时执行自定义逻辑。
-```csharp
-public IArchitectureLifecycle RegisterLifecycleHook(IArchitectureLifecycle hook)
-```
-
-**返回值:** 返回注册的生命周期钩子实例
-
-**特点:**
-
-- 生命周期钩子可以监听所有架构阶段变化
-- 只能在架构进入 Ready 阶段之前注册
-- 架构会按注册顺序通知所有钩子
-
-参数:
-
-- `hook`:生命周期钩子实例
-
-使用示例:
-
-```csharp
-// 定义生命周期钩子
-public class PerformanceMonitorHook : IArchitectureLifecycle
-{
- public void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
- {
- switch (phase)
- {
- case ArchitecturePhase.BeforeModelInit:
- Console.WriteLine("开始监控 Model 初始化性能");
- break;
- case ArchitecturePhase.AfterModelInit:
- Console.WriteLine("Model 初始化完成,停止监控");
- break;
- case ArchitecturePhase.Ready:
- Console.WriteLine("架构就绪,开始性能统计");
- break;
- }
- }
-}
-
-// 注册生命周期钩子
-var architecture = new GameArchitecture();
-var registeredHook = architecture.RegisterLifecycleHook(new PerformanceMonitorHook());
-architecture.Initialize();
-```
-
-**注意:** 生命周期钩子只能在架构进入 Ready 阶段之前注册。
-
-#### 属性
-
-**CurrentPhase**
-
-获取当前架构的阶段。
-```csharp
-public ArchitecturePhase CurrentPhase { get; private set; }
-```
-
-**特点:**
-
-- 只读属性,外部无法直接修改
-- 实时反映架构的当前状态
-- 可用于条件判断和状态检查
-
-使用示例:
-
-```csharp
-var architecture = new GameArchitecture();
-
-// 检查架构是否已就绪
-if (architecture.CurrentPhase == ArchitecturePhase.Ready)
-{
- Console.WriteLine("架构已就绪,可以开始游戏");
-}
-
-// 在异步操作中检查阶段变化
-await Task.Run(async () =>
-{
- while (architecture.CurrentPhase != ArchitecturePhase.Ready)
- {
- Console.WriteLine($"当前阶段: {architecture.CurrentPhase}");
- await Task.Delay(100);
- }
-});
-```
-
-**Context**
-
-获取架构上下文,提供对架构服务的访问。
-```csharp
-public IArchitectureContext Context { get; }
-```
-
-**特点:**
-
-- 提供对架构核心服务的访问
-- 包含事件总线、命令总线、查询总线等
-- 是架构内部服务的统一入口
-
-使用示例:
-
-```csharp
-// 通过 Context 访问服务
-var context = architecture.Context;
-var eventBus = context.EventBus;
-var commandBus = context.CommandBus;
-var queryBus = context.QueryBus;
-var environment = context.Environment;
-```
-
-#### 高级特性
-
-```csharp
-// 1. 使用自定义配置
-var config = new ArchitectureConfiguration
-{
- ArchitectureProperties = new ArchitectureProperties
- {
- StrictPhaseValidation = true, // 启用严格阶段验证
- AllowLateRegistration = false // 禁止就绪后注册组件
- }
-};
-var architecture = new GameArchitecture(configuration: config);
-
-// 2. 模块安装
-var module = new GameModule();
-architecture.InstallModule(module);
-
-// 3. 监听架构阶段变化
-public class GamePhaseListener : IArchitecturePhaseAware
-{
- public void OnArchitecturePhase(ArchitecturePhase phase)
- {
- switch (phase)
- {
- case ArchitecturePhase.Ready:
- Console.WriteLine("架构已就绪,可以开始游戏了");
- break;
- case ArchitecturePhase.Destroying:
- Console.WriteLine("架构正在销毁");
- break;
- }
- }
-}
-
-// 4. 生命周期钩子
-public class LifecycleHook : IArchitectureLifecycle
-{
- public void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
- {
- Console.WriteLine($"架构阶段变化: {phase}");
- }
-}
-
-// 5. 等待架构就绪
-public async Task WaitForArchitectureReady()
-{
- var architecture = new GameArchitecture();
- var initTask = architecture.InitializeAsync();
-
- // 可以在其他地方等待架构就绪
- await architecture.WaitUntilReadyAsync();
- Console.WriteLine("架构已就绪");
-}
-```
-
-### ArchitectureConfiguration 架构配置类
-
-架构配置类,用于配置架构的行为。
-
-**主要配置项:**
-
-```csharp
-public class ArchitectureConfiguration : IArchitectureConfiguration
-{
- public IArchitectureProperties ArchitectureProperties { get; set; } = new ArchitectureProperties();
- public IEnvironmentProperties EnvironmentProperties { get; set; } = new EnvironmentProperties();
- public ILoggerProperties LoggerProperties { get; set; } = new LoggerProperties();
-}
-
-public class ArchitectureProperties
-{
- public bool StrictPhaseValidation { get; set; } = false; // 严格阶段验证
- public bool AllowLateRegistration { get; set; } = true; // 允许延迟注册
-}
-```
-
-**使用示例:**
-
-```csharp
-var config = new ArchitectureConfiguration
-{
- ArchitectureProperties = new ArchitectureProperties
- {
- StrictPhaseValidation = true, // 启用严格阶段验证
- AllowLateRegistration = false // 禁止就绪后注册组件
- },
- LoggerProperties = new LoggerProperties
- {
- LoggerFactoryProvider = new ConsoleLoggerFactoryProvider() // 自定义日志工厂
- }
-};
-
-var architecture = new GameArchitecture(configuration: config);
-```
-
-### ArchitectureServices 架构服务类
-
-架构服务类,管理命令总线、查询总线、IOC容器和类型事件系统。
-
-**核心服务:**
-
-- `IIocContainer Container`:依赖注入容器
-- `IEventBus EventBus`:事件总线
-- `ICommandBus CommandBus`:命令总线
-- `IQueryBus QueryBus`:查询总线
-
-### ArchitectureContext 架构上下文类
-
-架构上下文类,提供对架构服务的访问。
-
-**功能:**
-
-- 统一访问架构核心服务
-- 管理服务实例的生命周期
-- 提供服务解析功能
-
-### GameContext 游戏上下文类
-
-游戏上下文类,管理架构上下文与类型的绑定关系。
-
-**功能:**
-
-- 维护架构类型与上下文实例的映射
-- 提供全局上下文访问
-- 支持多架构实例管理
-
-## 设计模式
-
-### 1. 依赖注入
-
-通过构造函数注入或容器解析获取架构实例。
-
-### 2. 控制反转 (IoC)
-
-使用内置 IoC 容器管理组件生命周期和依赖关系。
-
-### 3. 命令模式
-
-通过 `ICommand` 封装所有用户操作。
-
-### 4. 查询模式 (CQRS)
-
-通过 `IQuery` 分离查询和命令操作。
-
-### 5. 观察者模式
-
-通过事件系统实现组件间的松耦合通信。
-
-### 6. 阶段式生命周期管理
-
-通过 `ArchitecturePhase` 枚举和生命周期钩子管理架构状态。
-
-### 7. 组合优于继承
-
-通过接口组合获得不同能力,而不是深层继承链。
-
-### 8. 模块化设计
-
-通过 `IArchitectureModule` 实现架构的可扩展性。
-
-### 9. 工厂模式
-
-通过配置对象和工厂方法创建架构实例。
-
-## 最佳实践
-
-1. **保持架构类简洁**:只在 `Init()` 中注册组件,不要包含业务逻辑
-2. **合理划分职责**:
- - Model:数据和状态
- - System:业务逻辑和规则
- - Utility:无状态的工具方法
-3. **使用依赖注入**:通过构造函数注入架构实例,便于测试
-4. **事件命名规范**:使用过去式命名事件类,如 `PlayerDiedEvent`
-5. **避免循环依赖**:System 不应直接引用 System,应通过事件通信
-6. **使用模块扩展**:通过 `IArchitectureModule` 实现架构的可扩展性
-7. **Core 模块与平台解耦**:GFramework.Core 不包含 Godot 相关代码,Godot 集成在单独模块中
-8. **合理配置阶段验证**:根据项目需求配置 `StrictPhaseValidation` 和 `AllowLateRegistration`
-9. **及时处理初始化异常**:捕获并处理架构初始化过程中的异常
-10. **使用异步初始化**:对于需要加载大量资源的场景,优先使用 `InitializeAsync()`
-
-## 相关包
-
-- **command** - 命令模式实现
-- **query** - 查询模式实现
-- **events** - 事件系统
-- **ioc** - IoC 容器
-- **model** - 数据模型
-- **system** - 业务系统
-- **utility** - 工具类
-- **GFramework.Godot** - Godot 特定集成(GodotNode 扩展、GodotLogger 等)
-- **extensions** - 扩展方法
-- **logging** - 日志系统
-- **environment** - 环境管理
-
----
-
+# Architecture 包使用说明
+
+## 概述
+
+Architecture 包是整个框架的核心,提供了基于分层架构模式的应用程序架构基础。它实现了依赖注入(IoC)
+容器、组件生命周期管理,以及命令、查询、事件的统一调度机制。
+
+**注意**:本框架的 Core 模块与 Godot 解耦,Godot 相关集成在 GFramework.Godot 包中实现。
+
+## 核心接口
+
+### IArchitecture
+
+架构接口,定义了框架的核心功能契约。
+
+**主要职责:**
+
+- **组件注册**:注册 System、Model、Utility
+- **组件获取**:从容器中获取已注册的组件
+- **命令处理**:发送并执行命令
+- **查询处理**:发送并执行查询
+- **事件管理**:发送、注册、注销事件
+- **模块管理**:安装和管理架构模块
+- **生命周期管理**:管理架构的初始化、运行和销毁阶段
+
+**核心方法:**
+```csharp
+// 组件注册
+void RegisterSystem(TSystem system) where TSystem : ISystem;
+void RegisterModel(TModel model) where TModel : IModel;
+void RegisterUtility(TUtility utility) where TUtility : IUtility;
+
+// 组件获取(通过容器)
+T GetModel() where T : class, IModel;
+T GetSystem() where T : class, ISystem;
+T GetUtility() where T : class, IUtility;
+
+// 命令处理
+void SendCommand(ICommand command);
+TResult SendCommand(ICommand command);
+
+// 查询处理
+TResult SendQuery(IQuery query);
+
+// 事件管理
+void SendEvent() where T : new();
+void SendEvent(T e);
+IUnRegister RegisterEvent(Action onEvent);
+void UnRegisterEvent(Action onEvent);
+```
+
+### IArchitecturePhaseAware
+
+架构阶段感知接口,允许组件监听架构阶段变化。
+
+**核心方法:**
+```csharp
+void OnArchitecturePhase(ArchitecturePhase phase);
+```
+
+### IArchitectureModule
+
+架构模块接口,支持模块化架构扩展。
+
+**核心方法:**
+```csharp
+void Install(IArchitecture architecture);
+```
+
+### IAsyncInitializable
+
+异步初始化接口,支持组件异步初始化。
+
+**核心方法:**
+```csharp
+Task InitializeAsync();
+```
+
+## 核心类
+
+### Architecture 架构基类
+
+架构基类,实现了 `IArchitecture` 接口,提供完整的架构功能实现。
+
+**构造函数参数:**
+```csharp
+public abstract class Architecture(
+ IArchitectureConfiguration? configuration = null,
+ IEnvironment? environment = null,
+ IArchitectureServices? services = null,
+ IArchitectureContext? context = null
+)
+```
+
+**特性:**
+
+- **阶段式生命周期管理**
+ :支持多个架构阶段(BeforeUtilityInit、AfterUtilityInit、BeforeModelInit、AfterModelInit、BeforeSystemInit、AfterSystemInit、Ready、FailedInitialization、Destroying、Destroyed)
+- **模块安装系统**:支持通过 `InstallModule` 扩展架构功能
+- **异步初始化**:支持同步和异步两种初始化方式
+- **IoC 容器集成**:内置依赖注入容器
+- **事件系统集成**:集成类型化事件系统
+- **与平台无关**:Core 模块不依赖 Godot,可以在任何 .NET 环境中使用
+- **严格的阶段验证**:可配置的阶段转换验证机制
+- **组件生命周期管理**:自动管理组件的初始化和销毁
+
+**架构阶段:**
+```csharp
+public enum ArchitecturePhase
+{
+ None = 0, // 初始阶段
+ BeforeUtilityInit = 1, // 工具初始化前
+ AfterUtilityInit = 2, // 工具初始化后
+ BeforeModelInit = 3, // 模型初始化前
+ AfterModelInit = 4, // 模型初始化后
+ BeforeSystemInit = 5, // 系统初始化前
+ AfterSystemInit = 6, // 系统初始化后
+ Ready = 7, // 就绪状态
+ FailedInitialization = 8, // 初始化失败
+ Destroying = 9, // 正在销毁
+ Destroyed = 10 // 已销毁
+}
+```
+
+**初始化流程:**
+
+1. 创建架构实例(传入配置或使用默认配置)
+2. 初始化基础上下文和日志系统
+3. 调用用户自定义的 `Init()` 方法
+4. 按顺序初始化组件:
+ - 工具初始化(BeforeUtilityInit → AfterUtilityInit)
+ - 模型初始化(BeforeModelInit → AfterModelInit)
+ - 系统初始化(BeforeSystemInit → AfterSystemInit)
+5. 冻结 IOC 容器
+6. 进入 Ready 阶段
+
+**销毁流程:**
+
+1. 进入 Destroying 阶段
+2. 按注册逆序销毁所有实现了 `IDisposable` 的组件
+3. 进入 Destroyed 阶段
+4. 清理所有资源
+
+**使用示例:**
+
+```csharp
+// 1. 定义你的架构(继承 Architecture 基类)
+public class GameArchitecture : Architecture
+{
+ protected override void Init()
+ {
+ // 注册 Model
+ RegisterModel(new PlayerModel());
+ RegisterModel(new InventoryModel());
+
+ // 注册 System
+ RegisterSystem(new GameplaySystem());
+ RegisterSystem(new SaveSystem());
+
+ // 注册 Utility
+ RegisterUtility(new StorageUtility());
+ RegisterUtility(new TimeUtility());
+ }
+}
+
+// 2. 创建并初始化架构
+var architecture = new GameArchitecture();
+architecture.Initialize();
+
+// 或者异步初始化
+// var architecture = new GameArchitecture();
+// await architecture.InitializeAsync();
+
+// 3. 等待架构就绪
+await architecture.WaitUntilReadyAsync();
+
+// 4. 通过依赖注入使用架构
+// 在 Controller 或其他组件中获取架构实例
+using GFramework.Core.Abstractions.controller;
+using GFramework.SourceGenerators.Abstractions.rule;
+
+[ContextAware]
+public partial class GameController : IController
+{
+ public void Start()
+ {
+ // 获取 Model(通过 Context 属性访问架构)
+ var playerModel = Context.GetModel();
+
+ // 发送命令
+ Context.SendCommand(new StartGameCommand());
+
+ // 发送查询
+ var score = Context.SendQuery(new GetScoreQuery());
+
+ // 注册事件
+ Context.RegisterEvent(OnPlayerDied);
+ }
+
+ private void OnPlayerDied(PlayerDiedEvent e)
+ {
+ // 处理玩家死亡事件
+ }
+}
+```
+
+**核心方法与属性:**
+
+#### 初始化方法
+
+**Initialize()**
+
+同步初始化方法,阻塞当前线程直到初始化完成。
+```csharp
+public void Initialize()
+```
+
+**特点:**
+
+- 阻塞式初始化
+- 适用于简单场景或控制台应用
+- 初始化失败时抛出异常并进入 `FailedInitialization` 阶段
+
+使用示例:
+```csharp
+var architecture = new GameArchitecture();
+architecture.Initialize(); // 阻塞等待初始化完成
+```
+
+异常处理:如果初始化过程中发生异常,架构会进入 `FailedInitialization` 阶段。
+
+**InitializeAsync()**
+
+异步初始化方法,返回 Task 以便调用者可以等待初始化完成。
+```csharp
+public async Task InitializeAsync()
+```
+
+**特点:**
+
+- 非阻塞式初始化
+- 支持异步组件初始化
+- 适用于需要异步加载资源的场景
+- 初始化失败时抛出异常并进入 `FailedInitialization` 阶段
+
+使用示例:
+```csharp
+var architecture = new GameArchitecture();
+await architecture.InitializeAsync(); // 异步等待初始化完成
+```
+
+优势:
+- 支持异步初始化 Model 和 System
+- 可以利用异步 I/O 操作(如异步加载数据)
+- 提高初始化性能
+- 不会阻塞主线程
+
+#### 模块管理
+
+**InstallModule(IArchitectureModule module)**
+
+安装架构模块,用于扩展架构功能。
+```csharp
+public IArchitectureModule InstallModule(IArchitectureModule module)
+```
+
+**返回值:** 返回安装的模块实例
+
+**特点:**
+
+- 模块安装时会自动注册生命周期钩子
+- 模块可以注册额外的组件到架构中
+- 只能在架构进入 Ready 阶段之前安装模块
+
+参数:
+
+- `module`:要安装的模块实例
+
+使用示例:
+
+```csharp
+// 定义模块
+public class NetworkModule : IArchitectureModule
+{
+ public void Install(IArchitecture architecture)
+ {
+ // 注册网络相关的 System 和 Utility
+ architecture.RegisterSystem(new NetworkSystem());
+ architecture.RegisterUtility(new HttpClientUtility());
+ }
+}
+
+// 安装模块
+var architecture = new GameArchitecture();
+var installedModule = architecture.InstallModule(new NetworkModule());
+```
+
+#### 生命周期钩子
+
+**RegisterLifecycleHook(IArchitectureLifecycle hook)**
+
+注册生命周期钩子,用于在架构阶段变化时执行自定义逻辑。
+```csharp
+public IArchitectureLifecycle RegisterLifecycleHook(IArchitectureLifecycle hook)
+```
+
+**返回值:** 返回注册的生命周期钩子实例
+
+**特点:**
+
+- 生命周期钩子可以监听所有架构阶段变化
+- 只能在架构进入 Ready 阶段之前注册
+- 架构会按注册顺序通知所有钩子
+
+参数:
+
+- `hook`:生命周期钩子实例
+
+使用示例:
+
+```csharp
+// 定义生命周期钩子
+public class PerformanceMonitorHook : IArchitectureLifecycle
+{
+ public void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
+ {
+ switch (phase)
+ {
+ case ArchitecturePhase.BeforeModelInit:
+ Console.WriteLine("开始监控 Model 初始化性能");
+ break;
+ case ArchitecturePhase.AfterModelInit:
+ Console.WriteLine("Model 初始化完成,停止监控");
+ break;
+ case ArchitecturePhase.Ready:
+ Console.WriteLine("架构就绪,开始性能统计");
+ break;
+ }
+ }
+}
+
+// 注册生命周期钩子
+var architecture = new GameArchitecture();
+var registeredHook = architecture.RegisterLifecycleHook(new PerformanceMonitorHook());
+architecture.Initialize();
+```
+
+**注意:** 生命周期钩子只能在架构进入 Ready 阶段之前注册。
+
+#### 属性
+
+**CurrentPhase**
+
+获取当前架构的阶段。
+```csharp
+public ArchitecturePhase CurrentPhase { get; private set; }
+```
+
+**特点:**
+
+- 只读属性,外部无法直接修改
+- 实时反映架构的当前状态
+- 可用于条件判断和状态检查
+
+使用示例:
+
+```csharp
+var architecture = new GameArchitecture();
+
+// 检查架构是否已就绪
+if (architecture.CurrentPhase == ArchitecturePhase.Ready)
+{
+ Console.WriteLine("架构已就绪,可以开始游戏");
+}
+
+// 在异步操作中检查阶段变化
+await Task.Run(async () =>
+{
+ while (architecture.CurrentPhase != ArchitecturePhase.Ready)
+ {
+ Console.WriteLine($"当前阶段: {architecture.CurrentPhase}");
+ await Task.Delay(100);
+ }
+});
+```
+
+**Context**
+
+获取架构上下文,提供对架构服务的访问。
+```csharp
+public IArchitectureContext Context { get; }
+```
+
+**特点:**
+
+- 提供对架构核心服务的访问
+- 包含事件总线、命令总线、查询总线等
+- 是架构内部服务的统一入口
+
+使用示例:
+
+```csharp
+// 通过 Context 访问服务
+var context = architecture.Context;
+var eventBus = context.EventBus;
+var commandBus = context.CommandBus;
+var queryBus = context.QueryBus;
+var environment = context.Environment;
+```
+
+#### 高级特性
+
+```csharp
+// 1. 使用自定义配置
+var config = new ArchitectureConfiguration
+{
+ ArchitectureProperties = new ArchitectureProperties
+ {
+ StrictPhaseValidation = true, // 启用严格阶段验证
+ AllowLateRegistration = false // 禁止就绪后注册组件
+ }
+};
+var architecture = new GameArchitecture(configuration: config);
+
+// 2. 模块安装
+var module = new GameModule();
+architecture.InstallModule(module);
+
+// 3. 监听架构阶段变化
+public class GamePhaseListener : IArchitecturePhaseAware
+{
+ public void OnArchitecturePhase(ArchitecturePhase phase)
+ {
+ switch (phase)
+ {
+ case ArchitecturePhase.Ready:
+ Console.WriteLine("架构已就绪,可以开始游戏了");
+ break;
+ case ArchitecturePhase.Destroying:
+ Console.WriteLine("架构正在销毁");
+ break;
+ }
+ }
+}
+
+// 4. 生命周期钩子
+public class LifecycleHook : IArchitectureLifecycle
+{
+ public void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
+ {
+ Console.WriteLine($"架构阶段变化: {phase}");
+ }
+}
+
+// 5. 等待架构就绪
+public async Task WaitForArchitectureReady()
+{
+ var architecture = new GameArchitecture();
+ var initTask = architecture.InitializeAsync();
+
+ // 可以在其他地方等待架构就绪
+ await architecture.WaitUntilReadyAsync();
+ Console.WriteLine("架构已就绪");
+}
+```
+
+### ArchitectureConfiguration 架构配置类
+
+架构配置类,用于配置架构的行为。
+
+**主要配置项:**
+
+```csharp
+public class ArchitectureConfiguration : IArchitectureConfiguration
+{
+ public IArchitectureProperties ArchitectureProperties { get; set; } = new ArchitectureProperties();
+ public IEnvironmentProperties EnvironmentProperties { get; set; } = new EnvironmentProperties();
+ public ILoggerProperties LoggerProperties { get; set; } = new LoggerProperties();
+}
+
+public class ArchitectureProperties
+{
+ public bool StrictPhaseValidation { get; set; } = false; // 严格阶段验证
+ public bool AllowLateRegistration { get; set; } = true; // 允许延迟注册
+}
+```
+
+**使用示例:**
+
+```csharp
+var config = new ArchitectureConfiguration
+{
+ ArchitectureProperties = new ArchitectureProperties
+ {
+ StrictPhaseValidation = true, // 启用严格阶段验证
+ AllowLateRegistration = false // 禁止就绪后注册组件
+ },
+ LoggerProperties = new LoggerProperties
+ {
+ LoggerFactoryProvider = new ConsoleLoggerFactoryProvider() // 自定义日志工厂
+ }
+};
+
+var architecture = new GameArchitecture(configuration: config);
+```
+
+### ArchitectureServices 架构服务类
+
+架构服务类,管理命令总线、查询总线、IOC容器和类型事件系统。
+
+**核心服务:**
+
+- `IIocContainer Container`:依赖注入容器
+- `IEventBus EventBus`:事件总线
+- `ICommandBus CommandBus`:命令总线
+- `IQueryBus QueryBus`:查询总线
+
+### ArchitectureContext 架构上下文类
+
+架构上下文类,提供对架构服务的访问。
+
+**功能:**
+
+- 统一访问架构核心服务
+- 管理服务实例的生命周期
+- 提供服务解析功能
+
+### GameContext 游戏上下文类
+
+游戏上下文类,管理架构上下文与类型的绑定关系。
+
+**功能:**
+
+- 维护架构类型与上下文实例的映射
+- 提供全局上下文访问
+- 支持多架构实例管理
+
+## 设计模式
+
+### 1. 依赖注入
+
+通过构造函数注入或容器解析获取架构实例。
+
+### 2. 控制反转 (IoC)
+
+使用内置 IoC 容器管理组件生命周期和依赖关系。
+
+### 3. 命令模式
+
+通过 `ICommand` 封装所有用户操作。
+
+### 4. 查询模式 (CQRS)
+
+通过 `IQuery` 分离查询和命令操作。
+
+### 5. 观察者模式
+
+通过事件系统实现组件间的松耦合通信。
+
+### 6. 阶段式生命周期管理
+
+通过 `ArchitecturePhase` 枚举和生命周期钩子管理架构状态。
+
+### 7. 组合优于继承
+
+通过接口组合获得不同能力,而不是深层继承链。
+
+### 8. 模块化设计
+
+通过 `IArchitectureModule` 实现架构的可扩展性。
+
+### 9. 工厂模式
+
+通过配置对象和工厂方法创建架构实例。
+
+## 最佳实践
+
+1. **保持架构类简洁**:只在 `Init()` 中注册组件,不要包含业务逻辑
+2. **合理划分职责**:
+ - Model:数据和状态
+ - System:业务逻辑和规则
+ - Utility:无状态的工具方法
+3. **使用依赖注入**:通过构造函数注入架构实例,便于测试
+4. **事件命名规范**:使用过去式命名事件类,如 `PlayerDiedEvent`
+5. **避免循环依赖**:System 不应直接引用 System,应通过事件通信
+6. **使用模块扩展**:通过 `IArchitectureModule` 实现架构的可扩展性
+7. **Core 模块与平台解耦**:GFramework.Core 不包含 Godot 相关代码,Godot 集成在单独模块中
+8. **合理配置阶段验证**:根据项目需求配置 `StrictPhaseValidation` 和 `AllowLateRegistration`
+9. **及时处理初始化异常**:捕获并处理架构初始化过程中的异常
+10. **使用异步初始化**:对于需要加载大量资源的场景,优先使用 `InitializeAsync()`
+
+## 相关包
+
+- **command** - 命令模式实现
+- **query** - 查询模式实现
+- **events** - 事件系统
+- **ioc** - IoC 容器
+- **model** - 数据模型
+- **system** - 业务系统
+- **utility** - 工具类
+- **GFramework.Godot** - Godot 特定集成(GodotNode 扩展、GodotLogger 等)
+- **extensions** - 扩展方法
+- **logging** - 日志系统
+- **environment** - 环境管理
+
+---
+
**许可证**:Apache 2.0
\ No newline at end of file
diff --git a/docs/zh-CN/core/command.md b/docs/zh-CN/core/command.md
index 3f4252c..2caed75 100644
--- a/docs/zh-CN/core/command.md
+++ b/docs/zh-CN/core/command.md
@@ -1,447 +1,451 @@
-# Command 包使用说明
-
-## 概述
-
-Command 包实现了命令模式(Command Pattern),用于封装用户操作和业务逻辑。通过命令模式,可以将请求封装为对象,实现操作的参数化、队列化、日志记录、撤销等功能。
-
-命令系统是 GFramework CQRS 架构的重要组成部分,与事件系统和查询系统协同工作,实现完整的业务逻辑处理流程。
-
-## 核心接口
-
-### ICommand
-
-无返回值命令接口,定义了命令的基本契约。
-
-**核心方法:**
-
-```csharp
-void Execute(); // 执行命令
-```
-
-### ICommand``
-
-带返回值的命令接口,用于需要返回执行结果的命令。
-
-**核心方法:**
-
-```csharp
-TResult Execute(); // 执行命令并返回结果
-```
-
-## 核心类
-
-### AbstractCommand
-
-无返回值命令的抽象基类,提供了命令的基础实现。它继承自 ContextAwareBase,具有上下文感知能力。
-
-**核心方法:**
-
-```csharp
-void ICommand.Execute(); // 实现 ICommand 接口
-protected abstract void OnExecute(); // 抽象执行方法,由子类实现
-```
-
-**使用示例:**
-
-```csharp
-// 定义一个无返回值的基础命令
-public class SimpleCommand : AbstractCommand
-{
- protected override void OnExecute()
- {
- var playerModel = this.GetModel();
- playerModel.Health.Value = playerModel.MaxHealth.Value;
- this.SendEvent(new PlayerHealthRestoredEvent());
- }
-}
-
-// 使用命令
-public class GameController : IController
-{
- public IArchitecture GetArchitecture() => GameArchitecture.Interface;
-
- public void OnRestoreHealthButtonClicked()
- {
- this.SendCommand(new SimpleCommand());
- }
-}
-```
-
-### AbstractCommand``
-
-无输入参数但带返回值的命令基类。
-
-**核心方法:**
-
-```csharp
-TResult ICommand.Execute(); // 实现 ICommand 接口
-protected abstract TResult OnExecute(); // 抽象执行方法,由子类实现
-```
-
-**使用示例:**
-
-```csharp
-// 定义一个无输入但有返回值的命令
-public class GetPlayerHealthQuery : AbstractCommand
-{
- protected override int OnExecute()
- {
- var playerModel = this.GetModel();
- return playerModel.Health.Value;
- }
-}
-
-// 使用命令
-public class UISystem : AbstractSystem
-{
- protected override void OnInit()
- {
- this.RegisterEvent(OnUpdateUI);
- }
-
- private void OnUpdateUI(UpdateUIEvent e)
- {
- var health = this.SendCommand(new GetPlayerHealthQuery());
- Console.WriteLine($"Player health: {health}");
- }
-}
-```
-
-## 命令的生命周期
-
-1. **创建命令**:实例化命令对象,传入必要的参数
-2. **执行命令**:调用 `Execute()` 方法,内部委托给 `OnExecute()`
-3. **返回结果**:对于带返回值的命令,返回执行结果
-4. **命令销毁**:命令执行完毕后可以被垃圾回收
-
-**注意事项:**
-
-- 命令应该是无状态的,执行完即可丢弃
-- 避免在命令中保存长期引用
-- 命令执行应该是原子操作
-
-## CommandBus - 命令总线
-
-### 功能说明
-
-`CommandBus` 是命令执行的核心组件,负责发送和执行命令。
-
-**主要方法:**
-
-```csharp
-void Send(ICommand command); // 发送无返回值命令
-TResult Send(ICommand command); // 发送带返回值命令
-```
-
-**特点:**
-
-- 统一的命令执行入口
-- 支持同步命令执行
-- 与架构上下文集成
-
-### 使用示例
-
-```csharp
-// 通过架构获取命令总线
-var commandBus = architecture.Context.CommandBus;
-
-// 发送无返回值命令
-commandBus.Send(new StartGameCommand(1, "Player1"));
-
-// 发送带返回值命令
-var damage = commandBus.Send(new CalculateDamageCommand(100, 50));
-```
-
-## 命令基类变体
-
-框架提供了多种命令基类以满足不同需求:
-
-### AbstractCommand``
-
-带输入参数的无返回值命令类。通过 `ICommandInput` 接口传递参数。
-
-**核心方法:**
-
-```csharp
-void ICommand.Execute(); // 实现 ICommand 接口
-protected abstract void OnExecute(TInput input); // 抽象执行方法,接收输入参数
-```
-
-**使用示例:**
-
-```csharp
-// 定义输入对象
-public class StartGameInput : ICommandInput
-{
- public int LevelId { get; set; }
- public string PlayerName { get; set; }
-}
-
-// 定义命令
-public class StartGameCommand : AbstractCommand
-{
- protected override void OnExecute(StartGameInput input)
- {
- var playerModel = this.GetModel();
- var gameModel = this.GetModel();
-
- 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``
-
-既带输入参数又带返回值的命令类。
-
-**核心方法:**
-
-```csharp
-TResult ICommand.Execute(); // 实现 ICommand 接口
-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
-{
- protected override int OnExecute(CalculateDamageInput input)
- {
- var config = this.GetModel();
- 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``
-
-支持异步执行的带输入参数的无返回值命令基类。
-
-**核心方法:**
-
-```csharp
-Task IAsyncCommand.ExecuteAsync(); // 实现异步命令接口
-protected abstract Task OnExecuteAsync(TInput input); // 抽象异步执行方法
-```
-
-### AbstractAsyncCommand``
-
-支持异步执行的既带输入参数又带返回值的命令基类。
-
-**核心方法:**
-
-```csharp
-Task