From aab0995f4958b2a58d78c31a5d516aaad8f0d5fe Mon Sep 17 00:00:00 2001
From: GeWuYou <95328647+GeWuYou@users.noreply.github.com>
Date: Mon, 6 Apr 2026 10:12:59 +0800
Subject: [PATCH] docs(godot): add architecture integration and design pattern
docs
- Add documentation for Godot architecture integration, including AbstractArchitecture,
ArchitectureAnchor, and IGodotModule
- Describe basic usage: architecture creation, initialization, and anchor usage
- Provide advanced examples: module system, lifecycle hooks, and hot-reload support
- Document ContextAware usage for accessing architecture within nodes
- Include best practices for multi-architecture setups and common pitfalls
- Add architecture design patterns guide (MVC, MVVM, Command, etc.)
- Cover event-driven, DI, and service locator patterns with examples
Note:
- Normalize line endings to LF to fix inconsistent diffs caused by CRLF/LF mismatch
- No functional code changes
---
.../Logging/Formatters/DefaultLogFormatter.cs | 112 +-
GFramework.Ecs.Arch/INTEGRATION_PATTERN.md | 354 +-
.../MIGRATION_FROM_AUTO_TO_EXPLICIT.md | 628 +-
.../Internals/IsExternalInit.cs | 38 +-
.../best-practices/architecture-patterns.md | 6884 ++++++++---------
docs/zh-CN/best-practices/index.md | 982 +--
docs/zh-CN/best-practices/performance.md | 2728 +++----
docs/zh-CN/core/architecture.md | 324 +-
docs/zh-CN/core/command.md | 892 +--
docs/zh-CN/core/configuration.md | 1878 ++---
docs/zh-CN/core/events.md | 1202 +--
docs/zh-CN/core/index.md | 1250 +--
docs/zh-CN/core/pause.md | 1800 ++---
docs/zh-CN/core/property.md | 842 +-
docs/zh-CN/core/state-machine.md | 1164 +--
docs/zh-CN/core/system.md | 1324 ++--
docs/zh-CN/game/scene.md | 1316 ++--
docs/zh-CN/game/serialization.md | 1514 ++--
docs/zh-CN/game/ui.md | 1018 +--
docs/zh-CN/getting-started/quick-start.md | 646 +-
docs/zh-CN/godot/architecture.md | 1224 +--
.../context-aware-generator.md | 806 +-
docs/zh-CN/source-generators/index.md | 2114 ++---
.../source-generators/logging-generator.md | 682 +-
.../zh-CN/tutorials/godot-complete-project.md | 1622 ++--
docs/zh-CN/tutorials/pause-system.md | 2266 +++---
.../zh-CN/tutorials/state-machine-tutorial.md | 1492 ++--
refactor-scripts/folder-mappings.json | 1454 ++--
refactor-scripts/refactor-namespaces.ps1 | 912 +--
29 files changed, 19734 insertions(+), 19734 deletions(-)
diff --git a/GFramework.Core/Logging/Formatters/DefaultLogFormatter.cs b/GFramework.Core/Logging/Formatters/DefaultLogFormatter.cs
index ed5f8c2a..4c2dcef0 100644
--- a/GFramework.Core/Logging/Formatters/DefaultLogFormatter.cs
+++ b/GFramework.Core/Logging/Formatters/DefaultLogFormatter.cs
@@ -1,57 +1,57 @@
-using System;
-using System.Text;
-using GFramework.Core.Abstractions.Logging;
-
-namespace GFramework.Core.Logging.Formatters;
-
-///
-/// 默认日志格式化器,保持与现有格式兼容
-///
-public sealed class DefaultLogFormatter : ILogFormatter
-{
- private static readonly string[] LevelStrings =
- [
- "TRACE ",
- "DEBUG ",
- "INFO ",
- "WARNING",
- "ERROR ",
- "FATAL "
- ];
-
- ///
- /// 将日志条目格式化为默认格式
- ///
- /// 日志条目
- /// 格式化后的日志字符串
- public string Format(LogEntry entry)
- {
- var timestamp = entry.Timestamp.ToString("yyyy-MM-dd HH:mm:ss.fff");
- var levelStr = LevelStrings[(int)entry.Level];
- var sb = new StringBuilder();
-
- sb.Append('[').Append(timestamp).Append("] ")
- .Append(levelStr).Append(" [")
- .Append(entry.LoggerName).Append("] ")
- .Append(entry.Message);
-
- // 添加结构化属性
- var properties = entry.GetAllProperties();
- if (properties.Count > 0)
- {
- sb.Append(" |");
- foreach (var prop in properties)
- {
- sb.Append(' ').Append(prop.Key).Append('=').Append(prop.Value);
- }
- }
-
- // 添加异常信息
- if (entry.Exception != null)
- {
- sb.Append(global::System.Environment.NewLine).Append(entry.Exception);
- }
-
- return sb.ToString();
- }
+using System;
+using System.Text;
+using GFramework.Core.Abstractions.Logging;
+
+namespace GFramework.Core.Logging.Formatters;
+
+///
+/// 默认日志格式化器,保持与现有格式兼容
+///
+public sealed class DefaultLogFormatter : ILogFormatter
+{
+ private static readonly string[] LevelStrings =
+ [
+ "TRACE ",
+ "DEBUG ",
+ "INFO ",
+ "WARNING",
+ "ERROR ",
+ "FATAL "
+ ];
+
+ ///
+ /// 将日志条目格式化为默认格式
+ ///
+ /// 日志条目
+ /// 格式化后的日志字符串
+ public string Format(LogEntry entry)
+ {
+ var timestamp = entry.Timestamp.ToString("yyyy-MM-dd HH:mm:ss.fff");
+ var levelStr = LevelStrings[(int)entry.Level];
+ var sb = new StringBuilder();
+
+ sb.Append('[').Append(timestamp).Append("] ")
+ .Append(levelStr).Append(" [")
+ .Append(entry.LoggerName).Append("] ")
+ .Append(entry.Message);
+
+ // 添加结构化属性
+ var properties = entry.GetAllProperties();
+ if (properties.Count > 0)
+ {
+ sb.Append(" |");
+ foreach (var prop in properties)
+ {
+ sb.Append(' ').Append(prop.Key).Append('=').Append(prop.Value);
+ }
+ }
+
+ // 添加异常信息
+ if (entry.Exception != null)
+ {
+ sb.Append(global::System.Environment.NewLine).Append(entry.Exception);
+ }
+
+ return sb.ToString();
+ }
}
\ No newline at end of file
diff --git a/GFramework.Ecs.Arch/INTEGRATION_PATTERN.md b/GFramework.Ecs.Arch/INTEGRATION_PATTERN.md
index 471634c8..a38fac36 100644
--- a/GFramework.Ecs.Arch/INTEGRATION_PATTERN.md
+++ b/GFramework.Ecs.Arch/INTEGRATION_PATTERN.md
@@ -1,177 +1,177 @@
-# GFramework.Ecs.Arch - C# 标准集成方式
-
-## 为什么不使用 ModuleInitializer?
-
-`ModuleInitializer` 在 C# 中主要用于:
-
-1. **应用程序代码** - 初始化应用程序级别的状态
-2. **高级源生成器** - 编译时代码生成
-
-对于**库(Library)**来说,使用 `ModuleInitializer` 有以下问题:
-
-- ❌ 不符合 .NET 生态习惯
-- ❌ 缺乏显式控制
-- ❌ 难以测试和调试
-- ❌ 可能导致意外的副作用
-- ❌ 违反"显式优于隐式"原则
-
-## C# 中的标准做法
-
-### 1. 依赖注入扩展方法(推荐)
-
-这是 .NET 生态中最标准的做法,类似于:
-
-- ASP.NET Core: `services.AddMvc()`
-- Entity Framework: `services.AddDbContext()`
-- SignalR: `services.AddSignalR()`
-
-**优点:**
-
-- ✅ 符合 .NET 生态习惯
-- ✅ 显式、可控
-- ✅ 易于测试
-- ✅ 支持配置
-- ✅ 支持链式调用
-
-### 2. 使用方式
-
-#### 基本用法
-
-```csharp
-public class MyArchitecture : Architecture
-{
- protected override void OnConfigure()
- {
- // 显式添加 Arch ECS 支持
- Services.AddArch();
- }
-}
-```
-
-#### 带配置的用法
-
-```csharp
-public class MyArchitecture : Architecture
-{
- protected override void OnConfigure()
- {
- Services.AddArch(options =>
- {
- options.WorldCapacity = 2000;
- options.EnableStatistics = true;
- options.Priority = 50;
- });
- }
-}
-```
-
-#### 容器级别的用法
-
-```csharp
-var container = new MicrosoftDiContainer();
-container.AddArch(options =>
-{
- options.WorldCapacity = 1000;
-});
-```
-
-### 3. 对比其他方案
-
-#### Spring Boot Starter(Java)
-
-```java
-// Spring Boot 使用自动配置
-@SpringBootApplication
-public class Application {
- // 自动扫描并加载 starter
-}
-```
-
-#### ASP.NET Core(C#)
-
-```csharp
-// .NET 使用显式注册
-var builder = WebApplication.CreateBuilder(args);
-builder.Services.AddControllers();
-builder.Services.AddSwagger();
-```
-
-**C# 更倾向于显式注册**,因为:
-
-1. 更清晰的依赖关系
-2. 更好的 IDE 支持
-3. 更容易调试和测试
-4. 避免"魔法"行为
-
-### 4. 其他常见模式
-
-#### 4.1 Builder 模式
-
-```csharp
-var architecture = new ArchitectureBuilder()
- .AddArch()
- .AddLogging()
- .Build();
-```
-
-#### 4.2 Options 模式
-
-```csharp
-services.Configure(options =>
-{
- options.WorldCapacity = 2000;
-});
-```
-
-#### 4.3 静态工厂方法
-
-```csharp
-var module = ArchEcsModule.Create(options =>
-{
- options.WorldCapacity = 1000;
-});
-```
-
-## 迁移指南
-
-### 从 ModuleInitializer 迁移
-
-**之前(自动注册):**
-
-```csharp
-// 只需引入包,自动注册
-// 无需任何代码
-```
-
-**现在(显式注册):**
-
-```csharp
-public class MyArchitecture : Architecture
-{
- protected override void OnConfigure()
-{
- Services.AddArch();
- }
-}
-```
-
-### 优势
-
-1. **更清晰** - 一眼就能看出使用了哪些模块
-2. **更可控** - 可以决定何时、如何注册
-3. **更灵活** - 可以传递配置参数
-4. **更标准** - 符合 .NET 生态习惯
-
-## 总结
-
-C# 生态更倾向于**显式优于隐式**的设计哲学,因此:
-
-- ✅ **推荐**:使用扩展方法 `AddArch()`
-- ❌ **不推荐**:使用 `ModuleInitializer`
-
-这样的设计:
-
-1. 符合 .NET 生态习惯
-2. 提供更好的开发体验
-3. 更容易理解和维护
-4. 避免 CA2255 警告
+# GFramework.Ecs.Arch - C# 标准集成方式
+
+## 为什么不使用 ModuleInitializer?
+
+`ModuleInitializer` 在 C# 中主要用于:
+
+1. **应用程序代码** - 初始化应用程序级别的状态
+2. **高级源生成器** - 编译时代码生成
+
+对于**库(Library)**来说,使用 `ModuleInitializer` 有以下问题:
+
+- ❌ 不符合 .NET 生态习惯
+- ❌ 缺乏显式控制
+- ❌ 难以测试和调试
+- ❌ 可能导致意外的副作用
+- ❌ 违反"显式优于隐式"原则
+
+## C# 中的标准做法
+
+### 1. 依赖注入扩展方法(推荐)
+
+这是 .NET 生态中最标准的做法,类似于:
+
+- ASP.NET Core: `services.AddMvc()`
+- Entity Framework: `services.AddDbContext()`
+- SignalR: `services.AddSignalR()`
+
+**优点:**
+
+- ✅ 符合 .NET 生态习惯
+- ✅ 显式、可控
+- ✅ 易于测试
+- ✅ 支持配置
+- ✅ 支持链式调用
+
+### 2. 使用方式
+
+#### 基本用法
+
+```csharp
+public class MyArchitecture : Architecture
+{
+ protected override void OnConfigure()
+ {
+ // 显式添加 Arch ECS 支持
+ Services.AddArch();
+ }
+}
+```
+
+#### 带配置的用法
+
+```csharp
+public class MyArchitecture : Architecture
+{
+ protected override void OnConfigure()
+ {
+ Services.AddArch(options =>
+ {
+ options.WorldCapacity = 2000;
+ options.EnableStatistics = true;
+ options.Priority = 50;
+ });
+ }
+}
+```
+
+#### 容器级别的用法
+
+```csharp
+var container = new MicrosoftDiContainer();
+container.AddArch(options =>
+{
+ options.WorldCapacity = 1000;
+});
+```
+
+### 3. 对比其他方案
+
+#### Spring Boot Starter(Java)
+
+```java
+// Spring Boot 使用自动配置
+@SpringBootApplication
+public class Application {
+ // 自动扫描并加载 starter
+}
+```
+
+#### ASP.NET Core(C#)
+
+```csharp
+// .NET 使用显式注册
+var builder = WebApplication.CreateBuilder(args);
+builder.Services.AddControllers();
+builder.Services.AddSwagger();
+```
+
+**C# 更倾向于显式注册**,因为:
+
+1. 更清晰的依赖关系
+2. 更好的 IDE 支持
+3. 更容易调试和测试
+4. 避免"魔法"行为
+
+### 4. 其他常见模式
+
+#### 4.1 Builder 模式
+
+```csharp
+var architecture = new ArchitectureBuilder()
+ .AddArch()
+ .AddLogging()
+ .Build();
+```
+
+#### 4.2 Options 模式
+
+```csharp
+services.Configure(options =>
+{
+ options.WorldCapacity = 2000;
+});
+```
+
+#### 4.3 静态工厂方法
+
+```csharp
+var module = ArchEcsModule.Create(options =>
+{
+ options.WorldCapacity = 1000;
+});
+```
+
+## 迁移指南
+
+### 从 ModuleInitializer 迁移
+
+**之前(自动注册):**
+
+```csharp
+// 只需引入包,自动注册
+// 无需任何代码
+```
+
+**现在(显式注册):**
+
+```csharp
+public class MyArchitecture : Architecture
+{
+ protected override void OnConfigure()
+{
+ Services.AddArch();
+ }
+}
+```
+
+### 优势
+
+1. **更清晰** - 一眼就能看出使用了哪些模块
+2. **更可控** - 可以决定何时、如何注册
+3. **更灵活** - 可以传递配置参数
+4. **更标准** - 符合 .NET 生态习惯
+
+## 总结
+
+C# 生态更倾向于**显式优于隐式**的设计哲学,因此:
+
+- ✅ **推荐**:使用扩展方法 `AddArch()`
+- ❌ **不推荐**:使用 `ModuleInitializer`
+
+这样的设计:
+
+1. 符合 .NET 生态习惯
+2. 提供更好的开发体验
+3. 更容易理解和维护
+4. 避免 CA2255 警告
diff --git a/GFramework.Ecs.Arch/MIGRATION_FROM_AUTO_TO_EXPLICIT.md b/GFramework.Ecs.Arch/MIGRATION_FROM_AUTO_TO_EXPLICIT.md
index 0cb38430..744b2c93 100644
--- a/GFramework.Ecs.Arch/MIGRATION_FROM_AUTO_TO_EXPLICIT.md
+++ b/GFramework.Ecs.Arch/MIGRATION_FROM_AUTO_TO_EXPLICIT.md
@@ -1,314 +1,314 @@
-# GFramework.Ecs.Arch - 从自动注册到显式注册的迁移
-
-## 变更原因
-
-### 问题:CA2255 警告
-
-```
-warning CA2255: The 'ModuleInitializer' attribute is only intended to be used
-in application code or advanced source generator scenarios
-```
-
-### 为什么 ModuleInitializer 不适合库?
-
-在 C# 生态中,`ModuleInitializer` 主要用于:
-
-1. **应用程序代码** - 初始化应用程序级别的状态
-2. **高级源生成器** - 编译时代码生成
-
-对于**库(Library)**来说,使用 `ModuleInitializer` 有以下问题:
-
-- ❌ 不符合 .NET 生态习惯
-- ❌ 缺乏显式控制
-- ❌ 难以测试和调试
-- ❌ 可能导致意外的副作用
-- ❌ 违反"显式优于隐式"原则
-- ❌ 触发 CA2255 警告
-
-## C# 标准做法对比
-
-### Spring Boot(Java)- 自动配置
-
-```java
-@SpringBootApplication
-public class Application {
- // 自动扫描并加载 starter
-}
-```
-
-### ASP.NET Core(C#)- 显式注册
-
-```csharp
-var builder = WebApplication.CreateBuilder(args);
-builder.Services.AddControllers(); // 显式注册
-builder.Services.AddSwagger(); // 显式注册
-```
-
-**C# 更倾向于显式注册**,因为:
-
-1. ✅ 更清晰的依赖关系
-2. ✅ 更好的 IDE 支持
-3. ✅ 更容易调试和测试
-4. ✅ 避免"魔法"行为
-
-## 变更内容
-
-### 1. 移除 ModuleInitializer
-
-**之前:**
-
-```csharp
-// ArchModuleInitializer.cs
-[ModuleInitializer]
-public static void Initialize()
-{
- ArchitectureModuleRegistry.Register(() => new ArchEcsModule(enabled: true));
-}
-```
-
-**现在:**
-
-```csharp
-// 文件已删除
-```
-
-### 2. 新增扩展方法
-
-**新增:**
-
-```csharp
-// ArchExtensions.cs
-public static class ArchExtensions
-{
- ///
- /// 添加 Arch ECS 支持到架构服务中
- ///
- public static IArchitectureServices AddArch(
- this IArchitectureServices services,
- Action? configure = null)
- {
- var options = new ArchOptions();
- configure?.Invoke(options);
-
- ArchitectureModuleRegistry.Register(() => new ArchEcsModule(enabled: true));
-
- return services;
- }
-
- ///
- /// 添加 Arch ECS 支持到 IoC 容器中
- ///
- public static IIocContainer AddArch(
- this IIocContainer container,
- Action? configure = null)
- {
- var options = new ArchOptions();
- configure?.Invoke(options);
-
- ArchitectureModuleRegistry.Register(() => new ArchEcsModule(enabled: true));
-
- return container;
- }
-}
-```
-
-### 3. 更新使用方式
-
-#### 之前(自动注册)
-
-```csharp
-// 只需引入包,自动注册
-// 无需任何代码
-```
-
-#### 现在(显式注册)
-
-```csharp
-public class MyArchitecture : Architecture
-{
- protected override void OnConfigure()
- {
- // 显式注册
- Services.AddArch();
- }
-}
-```
-
-#### 带配置
-
-```csharp
-public class MyArchitecture : Architecture
-{
- protected override void OnConfigure()
- {
- Services.AddArch(options =>
- {
- options.WorldCapacity = 2000;
- options.EnableStatistics = true;
- options.Priority = 50;
- });
- }
-}
-```
-
-### 4. 更新测试
-
-**之前:**
-
-```csharp
-[Test]
-public void ArchEcsModule_Should_Be_Auto_Registered()
-{
- // 手动触发模块初始化器
- ArchModuleInitializer.Initialize();
-
- var services = new ArchitectureServices();
- services.ModuleManager.RegisterBuiltInModules(...);
- // ...
-}
-```
-
-**现在:**
-
-```csharp
-[Test]
-public void ArchEcsModule_Should_Be_Explicitly_Registered()
-{
- var services = new ArchitectureServices();
-
- // 显式注册
- services.AddArch();
-
- services.ModuleManager.RegisterBuiltInModules(...);
- // ...
-}
-```
-
-## 优势对比
-
-### 自动注册(ModuleInitializer)
-
-- ❌ 触发 CA2255 警告
-- ❌ 不符合 .NET 生态习惯
-- ❌ 缺乏显式控制
-- ❌ 难以测试
-- ❌ "魔法"行为
-
-### 显式注册(扩展方法)
-
-- ✅ 无警告
-- ✅ 符合 .NET 生态习惯
-- ✅ 显式、可控
-- ✅ 易于测试
-- ✅ 支持配置
-- ✅ 支持链式调用
-- ✅ 更好的 IDE 支持
-
-## 迁移指南
-
-### 对于现有用户
-
-如果你之前使用自动注册方式,需要进行以下更改:
-
-**步骤 1:更新包**
-
-```bash
-dotnet update package GeWuYou.GFramework.Ecs.Arch
-```
-
-**步骤 2:添加显式注册**
-
-```csharp
-public class MyArchitecture : Architecture
-{
- protected override void OnConfigure()
- {
- // 添加这一行
- Services.AddArch();
- }
-}
-```
-
-**步骤 3:(可选)添加配置**
-
-```csharp
-Services.AddArch(options =>
-{
- options.WorldCapacity = 2000;
- options.EnableStatistics = true;
-});
-```
-
-## 验证结果
-
-### 构建验证 ✅
-
-```bash
-dotnet build GFramework.sln
-# Build succeeded. 39 Warning(s), 0 Error(s)
-# 无 CA2255 警告
-```
-
-### 测试验证 ✅
-
-```bash
-dotnet test --filter "ExplicitRegistrationTests"
-# Pas 4, Failed: 0, Total: 4
-```
-
-**测试用例:**
-
-1. ✅ `ArchEcsModule_Should_Be_Explicitly_Registered` - 验证显式注册
-2. ✅ `World_Should_Be_Registered_In_Container` - 验证 World 注册
-3. ✅ `AddArch_Should_Accept_Configuration` - 验证配置支持
-4. ✅ `Container_AddArch_Should_Work` - 验证容器级别注册
-
-## 参考资料
-
-### .NET 生态中的类似实现
-
-1. **ASP.NET Core**
- ```csharp
- services.AddMvc();
- services.AddControllers();
- ```
-
-2. **Entity Framework Core**
- ```csharp
- services.AddDbContext();
- ```
-
-3. **SignalR**
- ```csharp
- services.AddSignalR();
- ```
-
-4. **Swagger**
- ```csharp
- services.AddSwaggerGen();
- ```
-
-### 相关文档
-
--N_PATTERN.md](INTEGRATION_PATTERN.md) - 集成模式详解
-
-- [README.md](README.md) - 使用指南
-- [CA2255 规则说明](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2255)
-
-## 总结
-
-通过从 `ModuleInitializer` 迁移到显式注册扩展方法:
-
-1. ✅ **消除警告** - 不再触发 CA2255
-2. ✅ **符合习惯** - 遵循 .NET 生态标准
-3. ✅ **更好控制** - 显式、可配置
-4. ✅ **易于测试** - 清晰的测试边界
-5. ✅ **更好体验** - IDE 支持、链式调用
-
-这是一个**破坏性变更**,但带来了更好的开发体验和更符合 .NET 生态的设计。
-
----
-
-**变更日期:** 2026-03-08
-**影响范围:** 所有使用 GFramework.Ecs.Arch 的项目
-**迁移难度:** 低(只需添加一行代码)
+# GFramework.Ecs.Arch - 从自动注册到显式注册的迁移
+
+## 变更原因
+
+### 问题:CA2255 警告
+
+```
+warning CA2255: The 'ModuleInitializer' attribute is only intended to be used
+in application code or advanced source generator scenarios
+```
+
+### 为什么 ModuleInitializer 不适合库?
+
+在 C# 生态中,`ModuleInitializer` 主要用于:
+
+1. **应用程序代码** - 初始化应用程序级别的状态
+2. **高级源生成器** - 编译时代码生成
+
+对于**库(Library)**来说,使用 `ModuleInitializer` 有以下问题:
+
+- ❌ 不符合 .NET 生态习惯
+- ❌ 缺乏显式控制
+- ❌ 难以测试和调试
+- ❌ 可能导致意外的副作用
+- ❌ 违反"显式优于隐式"原则
+- ❌ 触发 CA2255 警告
+
+## C# 标准做法对比
+
+### Spring Boot(Java)- 自动配置
+
+```java
+@SpringBootApplication
+public class Application {
+ // 自动扫描并加载 starter
+}
+```
+
+### ASP.NET Core(C#)- 显式注册
+
+```csharp
+var builder = WebApplication.CreateBuilder(args);
+builder.Services.AddControllers(); // 显式注册
+builder.Services.AddSwagger(); // 显式注册
+```
+
+**C# 更倾向于显式注册**,因为:
+
+1. ✅ 更清晰的依赖关系
+2. ✅ 更好的 IDE 支持
+3. ✅ 更容易调试和测试
+4. ✅ 避免"魔法"行为
+
+## 变更内容
+
+### 1. 移除 ModuleInitializer
+
+**之前:**
+
+```csharp
+// ArchModuleInitializer.cs
+[ModuleInitializer]
+public static void Initialize()
+{
+ ArchitectureModuleRegistry.Register(() => new ArchEcsModule(enabled: true));
+}
+```
+
+**现在:**
+
+```csharp
+// 文件已删除
+```
+
+### 2. 新增扩展方法
+
+**新增:**
+
+```csharp
+// ArchExtensions.cs
+public static class ArchExtensions
+{
+ ///
+ /// 添加 Arch ECS 支持到架构服务中
+ ///
+ public static IArchitectureServices AddArch(
+ this IArchitectureServices services,
+ Action? configure = null)
+ {
+ var options = new ArchOptions();
+ configure?.Invoke(options);
+
+ ArchitectureModuleRegistry.Register(() => new ArchEcsModule(enabled: true));
+
+ return services;
+ }
+
+ ///
+ /// 添加 Arch ECS 支持到 IoC 容器中
+ ///
+ public static IIocContainer AddArch(
+ this IIocContainer container,
+ Action? configure = null)
+ {
+ var options = new ArchOptions();
+ configure?.Invoke(options);
+
+ ArchitectureModuleRegistry.Register(() => new ArchEcsModule(enabled: true));
+
+ return container;
+ }
+}
+```
+
+### 3. 更新使用方式
+
+#### 之前(自动注册)
+
+```csharp
+// 只需引入包,自动注册
+// 无需任何代码
+```
+
+#### 现在(显式注册)
+
+```csharp
+public class MyArchitecture : Architecture
+{
+ protected override void OnConfigure()
+ {
+ // 显式注册
+ Services.AddArch();
+ }
+}
+```
+
+#### 带配置
+
+```csharp
+public class MyArchitecture : Architecture
+{
+ protected override void OnConfigure()
+ {
+ Services.AddArch(options =>
+ {
+ options.WorldCapacity = 2000;
+ options.EnableStatistics = true;
+ options.Priority = 50;
+ });
+ }
+}
+```
+
+### 4. 更新测试
+
+**之前:**
+
+```csharp
+[Test]
+public void ArchEcsModule_Should_Be_Auto_Registered()
+{
+ // 手动触发模块初始化器
+ ArchModuleInitializer.Initialize();
+
+ var services = new ArchitectureServices();
+ services.ModuleManager.RegisterBuiltInModules(...);
+ // ...
+}
+```
+
+**现在:**
+
+```csharp
+[Test]
+public void ArchEcsModule_Should_Be_Explicitly_Registered()
+{
+ var services = new ArchitectureServices();
+
+ // 显式注册
+ services.AddArch();
+
+ services.ModuleManager.RegisterBuiltInModules(...);
+ // ...
+}
+```
+
+## 优势对比
+
+### 自动注册(ModuleInitializer)
+
+- ❌ 触发 CA2255 警告
+- ❌ 不符合 .NET 生态习惯
+- ❌ 缺乏显式控制
+- ❌ 难以测试
+- ❌ "魔法"行为
+
+### 显式注册(扩展方法)
+
+- ✅ 无警告
+- ✅ 符合 .NET 生态习惯
+- ✅ 显式、可控
+- ✅ 易于测试
+- ✅ 支持配置
+- ✅ 支持链式调用
+- ✅ 更好的 IDE 支持
+
+## 迁移指南
+
+### 对于现有用户
+
+如果你之前使用自动注册方式,需要进行以下更改:
+
+**步骤 1:更新包**
+
+```bash
+dotnet update package GeWuYou.GFramework.Ecs.Arch
+```
+
+**步骤 2:添加显式注册**
+
+```csharp
+public class MyArchitecture : Architecture
+{
+ protected override void OnConfigure()
+ {
+ // 添加这一行
+ Services.AddArch();
+ }
+}
+```
+
+**步骤 3:(可选)添加配置**
+
+```csharp
+Services.AddArch(options =>
+{
+ options.WorldCapacity = 2000;
+ options.EnableStatistics = true;
+});
+```
+
+## 验证结果
+
+### 构建验证 ✅
+
+```bash
+dotnet build GFramework.sln
+# Build succeeded. 39 Warning(s), 0 Error(s)
+# 无 CA2255 警告
+```
+
+### 测试验证 ✅
+
+```bash
+dotnet test --filter "ExplicitRegistrationTests"
+# Pas 4, Failed: 0, Total: 4
+```
+
+**测试用例:**
+
+1. ✅ `ArchEcsModule_Should_Be_Explicitly_Registered` - 验证显式注册
+2. ✅ `World_Should_Be_Registered_In_Container` - 验证 World 注册
+3. ✅ `AddArch_Should_Accept_Configuration` - 验证配置支持
+4. ✅ `Container_AddArch_Should_Work` - 验证容器级别注册
+
+## 参考资料
+
+### .NET 生态中的类似实现
+
+1. **ASP.NET Core**
+ ```csharp
+ services.AddMvc();
+ services.AddControllers();
+ ```
+
+2. **Entity Framework Core**
+ ```csharp
+ services.AddDbContext();
+ ```
+
+3. **SignalR**
+ ```csharp
+ services.AddSignalR();
+ ```
+
+4. **Swagger**
+ ```csharp
+ services.AddSwaggerGen();
+ ```
+
+### 相关文档
+
+-N_PATTERN.md](INTEGRATION_PATTERN.md) - 集成模式详解
+
+- [README.md](README.md) - 使用指南
+- [CA2255 规则说明](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2255)
+
+## 总结
+
+通过从 `ModuleInitializer` 迁移到显式注册扩展方法:
+
+1. ✅ **消除警告** - 不再触发 CA2255
+2. ✅ **符合习惯** - 遵循 .NET 生态标准
+3. ✅ **更好控制** - 显式、可配置
+4. ✅ **易于测试** - 清晰的测试边界
+5. ✅ **更好体验** - IDE 支持、链式调用
+
+这是一个**破坏性变更**,但带来了更好的开发体验和更符合 .NET 生态的设计。
+
+---
+
+**变更日期:** 2026-03-08
+**影响范围:** 所有使用 GFramework.Ecs.Arch 的项目
+**迁移难度:** 低(只需添加一行代码)
diff --git a/GFramework.Game.Abstractions/Internals/IsExternalInit.cs b/GFramework.Game.Abstractions/Internals/IsExternalInit.cs
index 1de16c68..8a76104d 100644
--- a/GFramework.Game.Abstractions/Internals/IsExternalInit.cs
+++ b/GFramework.Game.Abstractions/Internals/IsExternalInit.cs
@@ -1,20 +1,20 @@
-// IsExternalInit.cs
-// This type is required to support init-only setters and record types
-// when targeting netstandard2.0 or older frameworks.
-
-#if !NET5_0_OR_GREATER
-using System.ComponentModel;
-
-// ReSharper disable CheckNamespace
-
-namespace System.Runtime.CompilerServices;
-
-///
-/// 提供一个占位符类型,用于支持 C# 9.0 的 init 访问器功能。
-/// 该类型在 .NET 5.0 及更高版本中已内置,因此仅在较低版本的 .NET 中定义。
-///
-[EditorBrowsable(EditorBrowsableState.Never)]
-internal static class IsExternalInit
-{
-}
+// IsExternalInit.cs
+// This type is required to support init-only setters and record types
+// when targeting netstandard2.0 or older frameworks.
+
+#if !NET5_0_OR_GREATER
+using System.ComponentModel;
+
+// ReSharper disable CheckNamespace
+
+namespace System.Runtime.CompilerServices;
+
+///
+/// 提供一个占位符类型,用于支持 C# 9.0 的 init 访问器功能。
+/// 该类型在 .NET 5.0 及更高版本中已内置,因此仅在较低版本的 .NET 中定义。
+///
+[EditorBrowsable(EditorBrowsableState.Never)]
+internal static class IsExternalInit
+{
+}
#endif
\ 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 a94580c0..c60930e9 100644
--- a/docs/zh-CN/best-practices/architecture-patterns.md
+++ b/docs/zh-CN/best-practices/architecture-patterns.md
@@ -1,3443 +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 = this.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
- this.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 = this.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
- };
-
- 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
- };
- }
-}
-
-// 使用查询
-[ContextAware]
-public partial class CharacterPanelController : IController
-{
- 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 监听事件
-[ContextAware]
-public partial class UIController : IController
-{
- private IUnRegisterList _unregisterList = new UnRegisterList();
-
- public void Initialize()
- {
- // 监听成就解锁事件
- this.RegisterEvent(OnAchievementUnlocked)
- .AddToUnregisterList(_unregisterList);
-
- // 监听玩家死亡事件
- this.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 = this.GetModel();
- 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);
- }
-}
-
-// 使用状态机
-[ContextAware]
-public partial class GameController : IController
-{
- public async Task StartGame()
- {
- var stateMachine = this.GetSystem();
- await stateMachine.ChangeToAsync();
- }
-
- public async Task PauseGame()
- {
- var stateMachine = this.GetSystem();
- await stateMachine.ChangeToAsync();
- }
-
- public async Task ResumeGame()
- {
- var stateMachine = this.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 = this.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);
- this.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 = this.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
+ this.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 = this.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
+ };
+
+ 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
+ };
+ }
+}
+
+// 使用查询
+[ContextAware]
+public partial class CharacterPanelController : IController
+{
+ 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 监听事件
+[ContextAware]
+public partial class UIController : IController
+{
+ private IUnRegisterList _unregisterList = new UnRegisterList();
+
+ public void Initialize()
+ {
+ // 监听成就解锁事件
+ this.RegisterEvent(OnAchievementUnlocked)
+ .AddToUnregisterList(_unregisterList);
+
+ // 监听玩家死亡事件
+ this.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 = this.GetModel();
+ 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);
+ }
+}
+
+// 使用状态机
+[ContextAware]
+public partial class GameController : IController
+{
+ public async Task StartGame()
+ {
+ var stateMachine = this.GetSystem();
+ await stateMachine.ChangeToAsync();
+ }
+
+ public async Task PauseGame()
+ {
+ var stateMachine = this.GetSystem();
+ await stateMachine.ChangeToAsync();
+ }
+
+ public async Task ResumeGame()
+ {
+ var stateMachine = this.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 = this.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);
+ this.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 5e85b09c..c11f8fb7 100644
--- a/docs/zh-CN/best-practices/index.md
+++ b/docs/zh-CN/best-practices/index.md
@@ -1,491 +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;
- }
-}
-
-using GFramework.Core.Abstractions.Controller;
-using GFramework.SourceGenerators.Abstractions.Rule;
-
-[ContextAware]
-public partial class PlayerController : IController
-{
- // Controller:连接 UI 和逻辑
- public void Initialize()
- {
- var player = this.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 = this.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 = this.GetModel();
- model.Health.Value -= 1;
-}
-
-// ✅ 高效:缓存引用
-private PlayerModel _playerModel;
-
-public void Initialize()
-{
- _playerModel = this.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 = this.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 = this.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 = this.GetModel();
+ model.Health.Value -= 1;
+}
+
+// ✅ 高效:缓存引用
+private PlayerModel _playerModel;
+
+public void Initialize()
+{
+ _playerModel = this.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());
+ }
+}
+```
+
+---
+
+遵循这些最佳实践将帮助你构建可维护、高效、可扩展的应用程序。
diff --git a/docs/zh-CN/best-practices/performance.md b/docs/zh-CN/best-practices/performance.md
index b1dfd7ab..9aac68b3 100644
--- a/docs/zh-CN/best-practices/performance.md
+++ b/docs/zh-CN/best-practices/performance.md
@@ -1,1364 +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
-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 = this.GetModel<PlayerModel>();
-
- // 使用 UnRegisterList 管理订阅
- this.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()
- {
- // 订阅事件但从不取消订阅
- this.RegisterEvent<PlayerDamagedEvent>(OnPlayerDamaged);
-
- var playerModel = this.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 = this.GetModel<PlayerModel>();
+
+ // 使用 UnRegisterList 管理订阅
+ this.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()
+ {
+ // 订阅事件但从不取消订阅
+ this.RegisterEvent<PlayerDamagedEvent>(OnPlayerDamaged);
+
+ var playerModel = this.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 066dc7d6..671e847a 100644
--- a/docs/zh-CN/core/architecture.md
+++ b/docs/zh-CN/core/architecture.md
@@ -1,19 +1,19 @@
-# Architecture 架构详解
-
-> 深入了解 GFramework 的核心架构设计和实现
-
-## 目录
-
-- [概述](#概述)
-- [架构设计](#架构设计)
-- [生命周期管理](#生命周期管理)
-- [组件注册](#组件注册)
-- [模块系统](#模块系统)
-- [最佳实践](#最佳实践)
-- [API 参考](#api-参考)
-
-## 概述
-
+# Architecture 架构详解
+
+> 深入了解 GFramework 的核心架构设计和实现
+
+## 目录
+
+- [概述](#概述)
+- [架构设计](#架构设计)
+- [生命周期管理](#生命周期管理)
+- [组件注册](#组件注册)
+- [模块系统](#模块系统)
+- [最佳实践](#最佳实践)
+- [API 参考](#api-参考)
+
+## 概述
+
Architecture 是 GFramework 的核心类,负责管理整个应用的生命周期、组件注册和模块管理。从 v1.1.0 开始,Architecture
采用模块化设计,将职责分离到专门的协作者中。
@@ -21,54 +21,54 @@ Architecture 是 GFramework 的核心类,负责管理整个应用的生命周期
> - `ArchitectureServices` 是公开的基础服务入口,负责容器、事件总线、命令执行器、查询执行器和服务模块管理
> - `ArchitectureComponentRegistry` 是内部组件注册器,专门负责 System / Model / Utility 的注册与生命周期接入
> - 两者不是同一层职责,不要混用
-
-### 设计目标
-
-- **单一职责**: 每个管理器只负责一个明确的功能
-- **类型安全**: 基于泛型的组件获取和注册
-- **生命周期管理**: 自动的初始化和销毁机制
-- **可扩展性**: 支持模块和钩子扩展
-- **向后兼容**: 保持公共 API 稳定
-
-### 核心组件
-
-```
+
+### 设计目标
+
+- **单一职责**: 每个管理器只负责一个明确的功能
+- **类型安全**: 基于泛型的组件获取和注册
+- **生命周期管理**: 自动的初始化和销毁机制
+- **可扩展性**: 支持模块和钩子扩展
+- **向后兼容**: 保持公共 API 稳定
+
+### 核心组件
+
+```
Architecture (核心协调器)
├── ArchitectureBootstrapper (初始化基础设施编排)
├── ArchitectureLifecycle (生命周期管理)
├── ArchitectureComponentRegistry (组件注册)
└── ArchitectureModules (模块管理)
-```
-
-## 架构设计
-
-### 设计模式
-
-Architecture 采用以下设计模式:
-
+```
+
+## 架构设计
+
+### 设计模式
+
+Architecture 采用以下设计模式:
+
1. **组合模式 (Composition)**: Architecture 组合多个内部协作者
2. **委托模式 (Delegation)**: 方法调用委托给专门的管理器
3. **协调器模式 (Coordinator)**: Architecture 作为协调器统一对外接口
-
-### 类图
-
-```
-┌─────────────────────────────────────────────────────┐
+
+### 类图
+
+```
+┌─────────────────────────────────────────────────────┐
│ Architecture │
│ - _bootstrapper: ArchitectureBootstrapper │
│ - _lifecycle: ArchitectureLifecycle │
│ - _componentRegistry: ArchitectureComponentRegistry│
│ - _modules: ArchitectureModules │
-│ - _logger: ILogger │
-│ │
-│ + RegisterSystem() │
-│ + RegisterModel() │
-│ + RegisterUtility() │
-│ + InstallModule() │
-│ + InitializeAsync() │
-│ + DestroyAsync() │
-│ + event PhaseChanged │
-└─────────────────────────────────────────────────────┘
+│ - _logger: ILogger │
+│ │
+│ + RegisterSystem() │
+│ + RegisterModel() │
+│ + RegisterUtility() │
+│ + InstallModule() │
+│ + InitializeAsync() │
+│ + DestroyAsync() │
+│ + event PhaseChanged │
+└─────────────────────────────────────────────────────┘
│ │ │ │
│ │ │ │
▼ ▼ ▼ ▼
@@ -80,13 +80,13 @@ Architecture 采用以下设计模式:
│ - 上下文绑定 │ │ - 组件初始化 │ │ - Utility 注册│ │ │
│ - 容器冻结 │ │ - 就绪/销毁协调 │ │ - 生命周期接入│ │ │
└──────────────┘ └──────────────────┘ └──────────────┘ └──────────────┘
-```
-
-### 构造函数初始化
-
-从 v1.1.0 开始,所有管理器在构造函数中初始化:
-
-```csharp
+```
+
+### 构造函数初始化
+
+从 v1.1.0 开始,所有管理器在构造函数中初始化:
+
+```csharp
protected Architecture(
IArchitectureConfiguration? configuration = null,
IEnvironment? environment = null,
@@ -109,94 +109,94 @@ protected Architecture(
_modules = new ArchitectureModules(this, resolvedServices, _logger);
}
```
-
-**优势**:
-
-- 消除 `null!` 断言,提高代码安全性
-- 对象在构造后立即可用
-- 符合"构造即完整"原则
-- 可以在 InitializeAsync 之前访问事件
-
-## 生命周期管理
-
-### 架构阶段
-
-Architecture 定义了 11 个生命周期阶段:
-
-| 阶段 | 说明 | 触发时机 |
-|------------------------|--------------|------------------|
-| `None` | 初始状态 | 构造函数完成后 |
-| `BeforeUtilityInit` | Utility 初始化前 | 开始初始化 Utility |
-| `AfterUtilityInit` | Utility 初始化后 | 所有 Utility 初始化完成 |
-| `BeforeModelInit` | Model 初始化前 | 开始初始化 Model |
-| `AfterModelInit` | Model 初始化后 | 所有 Model 初始化完成 |
-| `BeforeSystemInit` | System 初始化前 | 开始初始化 System |
-| `AfterSystemInit` | System 初始化后 | 所有 System 初始化完成 |
-| `Ready` | 就绪状态 | 所有组件初始化完成 |
-| `Destroying` | 销毁中 | 开始销毁 |
-| `Destroyed` | 已销毁 | 销毁完成 |
-| `FailedInitialization` | 初始化失败 | 初始化过程中发生异常 |
-
-### 阶段转换
-
-```
-正常流程:
-None → BeforeUtilityInit → AfterUtilityInit → BeforeModelInit → AfterModelInit
- → BeforeSystemInit → AfterSystemInit → Ready → Destroying → Destroyed
-
-异常流程:
-Any → FailedInitialization
-```
-
-### 阶段事件
-
-可以通过 `PhaseChanged` 事件监听阶段变化:
-
-```csharp
-public class MyArchitecture : Architecture
-{
- protected override void OnInitialize()
- {
- // 监听阶段变化
- PhaseChanged += phase =>
- {
- Console.WriteLine($"Phase changed to: {phase}");
- };
- }
-}
-```
-
-### 生命周期钩子
-
-实现 `IArchitectureLifecycleHook` 接口可以在阶段变化时执行自定义逻辑:
-
-```csharp
-public class MyLifecycleHook : IArchitectureLifecycleHook
-{
- public void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
- {
- switch (phase)
- {
- case ArchitecturePhase.Ready:
- Console.WriteLine("Architecture is ready!");
- break;
- case ArchitecturePhase.Destroying:
- Console.WriteLine("Architecture is being destroyed!");
- break;
- }
- }
-}
-
-// 注册钩子
-architecture.RegisterLifecycleHook(new MyLifecycleHook());
-```
-
-### 初始化流程
-
-```
-1. 创建 Architecture 实例
- └─> 构造函数初始化管理器
-
+
+**优势**:
+
+- 消除 `null!` 断言,提高代码安全性
+- 对象在构造后立即可用
+- 符合"构造即完整"原则
+- 可以在 InitializeAsync 之前访问事件
+
+## 生命周期管理
+
+### 架构阶段
+
+Architecture 定义了 11 个生命周期阶段:
+
+| 阶段 | 说明 | 触发时机 |
+|------------------------|--------------|------------------|
+| `None` | 初始状态 | 构造函数完成后 |
+| `BeforeUtilityInit` | Utility 初始化前 | 开始初始化 Utility |
+| `AfterUtilityInit` | Utility 初始化后 | 所有 Utility 初始化完成 |
+| `BeforeModelInit` | Model 初始化前 | 开始初始化 Model |
+| `AfterModelInit` | Model 初始化后 | 所有 Model 初始化完成 |
+| `BeforeSystemInit` | System 初始化前 | 开始初始化 System |
+| `AfterSystemInit` | System 初始化后 | 所有 System 初始化完成 |
+| `Ready` | 就绪状态 | 所有组件初始化完成 |
+| `Destroying` | 销毁中 | 开始销毁 |
+| `Destroyed` | 已销毁 | 销毁完成 |
+| `FailedInitialization` | 初始化失败 | 初始化过程中发生异常 |
+
+### 阶段转换
+
+```
+正常流程:
+None → BeforeUtilityInit → AfterUtilityInit → BeforeModelInit → AfterModelInit
+ → BeforeSystemInit → AfterSystemInit → Ready → Destroying → Destroyed
+
+异常流程:
+Any → FailedInitialization
+```
+
+### 阶段事件
+
+可以通过 `PhaseChanged` 事件监听阶段变化:
+
+```csharp
+public class MyArchitecture : Architecture
+{
+ protected override void OnInitialize()
+ {
+ // 监听阶段变化
+ PhaseChanged += phase =>
+ {
+ Console.WriteLine($"Phase changed to: {phase}");
+ };
+ }
+}
+```
+
+### 生命周期钩子
+
+实现 `IArchitectureLifecycleHook` 接口可以在阶段变化时执行自定义逻辑:
+
+```csharp
+public class MyLifecycleHook : IArchitectureLifecycleHook
+{
+ public void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
+ {
+ switch (phase)
+ {
+ case ArchitecturePhase.Ready:
+ Console.WriteLine("Architecture is ready!");
+ break;
+ case ArchitecturePhase.Destroying:
+ Console.WriteLine("Architecture is being destroyed!");
+ break;
+ }
+ }
+}
+
+// 注册钩子
+architecture.RegisterLifecycleHook(new MyLifecycleHook());
+```
+
+### 初始化流程
+
+```
+1. 创建 Architecture 实例
+ └─> 构造函数初始化管理器
+
2. 调用 InitializeAsync() 或 Initialize()
├─> ArchitectureBootstrapper 准备基础设施
│ ├─> 初始化环境 (Environment.Initialize())
@@ -211,14 +211,14 @@ architecture.RegisterLifecycleHook(new MyLifecycleHook());
│ └─> BeforeSystemInit → 初始化 System → AfterSystemInit
├─> CompleteInitialization() 冻结 IoC 容器
└─> 进入 Ready 阶段
-
-3. 等待就绪 (可选)
- └─> await architecture.WaitUntilReadyAsync()
-```
-
-### 销毁流程
-
-```
+
+3. 等待就绪 (可选)
+ └─> await architecture.WaitUntilReadyAsync()
+```
+
+### 销毁流程
+
+```
1. 调用 DestroyAsync() 或 Destroy()
├─> 检查当前阶段 (如果是 None 或已销毁则直接返回)
├─> 进入 Destroying 阶段
@@ -229,11 +229,11 @@ architecture.RegisterLifecycleHook(new MyLifecycleHook());
├─> 进入 Destroyed 阶段
└─> 清空 IoC 容器
```
-
----
-
-**版本**: 1.1.0
-**更新日期**: 2026-03-17
-**相关文档**:
-
-- [核心框架概述](./index.md)
+
+---
+
+**版本**: 1.1.0
+**更新日期**: 2026-03-17
+**相关文档**:
+
+- [核心框架概述](./index.md)
diff --git a/docs/zh-CN/core/command.md b/docs/zh-CN/core/command.md
index f4ec2bce..50303cde 100644
--- a/docs/zh-CN/core/command.md
+++ b/docs/zh-CN/core/command.md
@@ -1,123 +1,123 @@
-# 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());
- }
-}
-
-// 使用命令
-using GFramework.Core.Abstractions.Controller;
-using GFramework.SourceGenerators.Abstractions.Rule;
-
-[ContextAware]
-public partial class GameController : IController
-{
- 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}");
- }
-}
-```
-
+# 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());
+ }
+}
+
+// 使用命令
+using GFramework.Core.Abstractions.Controller;
+using GFramework.SourceGenerators.Abstractions.Rule;
+
+[ContextAware]
+public partial class GameController : IController
+{
+ 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. **命令销毁**:命令执行完毕后可以被垃圾回收
-
-**注意事项:**
-
+
+1. **创建命令**:实例化命令对象,传入必要的参数
+2. **执行命令**:调用 `Execute()` 方法,内部委托给 `OnExecute()`
+3. **返回结果**:对于带返回值的命令,返回执行结果
+4. **命令销毁**:命令执行完毕后可以被垃圾回收
+
+**注意事项:**
+
- 命令应该是无状态的,执行完即可丢弃
- 避免在命令中保存长期引用
- 命令执行应该是原子操作
@@ -145,331 +145,331 @@ public sealed class DamagePlayerCommand(int amount) : AbstractCommand
- Store 负责统一归约状态变化
完整示例见 [`state-management`](./state-management)。
-
-## 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());
- }
-}
-
-// 使用命令
-using GFramework.Core.Abstractions.Controller;
-using GFramework.SourceGenerators.Abstractions.Rule;
-
-[ContextAware]
-public partial class GameController : IController
-{
- 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 IAsyncCommand.ExecuteAsync(); // 实现异步命令接口
-protected abstract Task OnExecuteAsync(TInput input); // 抽象异步执行方法
-```
-
-**使用示例:**
-
-```csharp
-// 定义输入对象
-public class LoadSaveDataInput : ICommandInput
-{
- public string SaveSlot { get; set; }
-}
-
-// 定义异步命令
-public class LoadSaveDataCommand : AbstractAsyncCommand
-{
- protected override async Task OnExecuteAsync(LoadSaveDataInput input)
- {
- var storage = this.GetUtility();
- return await storage.LoadSaveDataAsync(input.SaveSlot);
- }
-}
-
-// 使用异步命令
-public class SaveSystem : AbstractSystem
-{
- protected override void OnInit()
- {
- this.RegisterEvent(OnLoadGameRequest);
- }
-
- private async void OnLoadGameRequest(LoadGameRequestEvent e)
- {
- var input = new LoadSaveDataInput { SaveSlot = e.SaveSlot };
- var saveData = await this.SendCommandAsync(new LoadSaveDataCommand { Input = input });
-
- if (saveData != null)
- {
- this.SendEvent(new GameLoadedEvent { SaveData = saveData });
- }
- }
-}
-```
-
-## 命令处理器执行
-
-所有发送给命令总线的命令最终都会通过 `CommandExecutor` 来执行:
-
-```csharp
-public class CommandExecutor
-{
- public static void Execute(ICommand command)
- {
- command.Execute();
- }
-
- public static TResult Execute