mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-24 12:33:30 +08:00
docs(core): 更新核心架构文档完善命令事件系统说明
- 重构架构文档增加模块管理和生命周期管理说明 - 更新命令系统文档移除输入参数结构简化命令定义 - 完善事件系统文档添加事件总线和注销功能说明 - 补充IoC容器文档增加多实例注册和单例管理说明 - 优化示例代码展示架构初始化和组件获取方式 - 添加配置选项说明和最佳实践建议
This commit is contained in:
parent
4be7f7a731
commit
7a18d9459b
@ -2,24 +2,26 @@
|
|||||||
|
|
||||||
## 概述
|
## 概述
|
||||||
|
|
||||||
Architecture 包是整个框架的核心,提供了基于 MVC 架构模式的应用程序架构基础。它实现了依赖注入(IoC)
|
Architecture 包是整个框架的核心,提供了基于分层架构模式的应用程序架构基础。它实现了依赖注入(IoC)
|
||||||
容器、组件生命周期管理,以及命令、查询、事件的统一调度机制。
|
容器、组件生命周期管理,以及命令、查询、事件的统一调度机制。
|
||||||
|
|
||||||
**注意**:本框架的 Core 模块与 Godot 解耦,Godot 相关集成在 GFramework.Godot 包中实现。
|
**注意**:本框架的 Core 模块与 Godot 解耦,Godot 相关集成在 GFramework.Godot 包中实现。
|
||||||
|
|
||||||
## 核心接口
|
## 核心接口
|
||||||
|
|
||||||
### IArchitecture
|
### IArchitecture
|
||||||
|
|
||||||
架构接口,定义了框架的核心功能契约。
|
架构接口,定义了框架的核心功能契约。
|
||||||
|
|
||||||
**主要职责:**
|
**主要职责:**
|
||||||
|
|
||||||
- 组件注册:注册 System、Model、Utility
|
- **组件注册**:注册 System、Model、Utility
|
||||||
- 组件获取:从容器中获取已注册的组件
|
- **组件获取**:从容器中获取已注册的组件
|
||||||
- 命令处理:发送并执行命令
|
- **命令处理**:发送并执行命令
|
||||||
- 查询处理:发送并执行查询
|
- **查询处理**:发送并执行查询
|
||||||
- 事件管理:发送、注册、注销事件
|
- **事件管理**:发送、注册、注销事件
|
||||||
|
- **模块管理**:安装和管理架构模块
|
||||||
|
- **生命周期管理**:管理架构的初始化、运行和销毁阶段
|
||||||
|
|
||||||
**核心方法:**
|
**核心方法:**
|
||||||
```csharp
|
```csharp
|
||||||
@ -49,27 +51,27 @@ void UnRegisterEvent<T>(Action<T> onEvent);
|
|||||||
|
|
||||||
### IArchitecturePhaseAware
|
### IArchitecturePhaseAware
|
||||||
|
|
||||||
架构阶段感知接口,允许组件监听架构阶段变化。
|
架构阶段感知接口,允许组件监听架构阶段变化。
|
||||||
|
|
||||||
**核心方法:**
|
**核心方法:**
|
||||||
```csharp
|
```csharp
|
||||||
void OnArchitecturePhase(ArchitecturePhase phase);
|
void OnArchitecturePhase(ArchitecturePhase phase);
|
||||||
```
|
```
|
||||||
|
|
||||||
### IArchitectureModule
|
### IArchitectureModule
|
||||||
|
|
||||||
架构模块接口,支持模块化架构扩展。
|
架构模块接口,支持模块化架构扩展。
|
||||||
|
|
||||||
**核心方法:**
|
**核心方法:**
|
||||||
```csharp
|
```csharp
|
||||||
void Install(IArchitecture architecture);
|
void Install(IArchitecture architecture);
|
||||||
```
|
```
|
||||||
|
|
||||||
### IAsyncInitializable
|
### IAsyncInitializable
|
||||||
|
|
||||||
异步初始化接口,支持组件异步初始化。
|
异步初始化接口,支持组件异步初始化。
|
||||||
|
|
||||||
**核心方法:**
|
**核心方法:**
|
||||||
```csharp
|
```csharp
|
||||||
Task InitializeAsync();
|
Task InitializeAsync();
|
||||||
```
|
```
|
||||||
@ -78,9 +80,9 @@ Task InitializeAsync();
|
|||||||
|
|
||||||
### Architecture 架构基类
|
### Architecture 架构基类
|
||||||
|
|
||||||
架构基类,实现了 `IArchitecture` 接口,提供完整的架构功能实现。
|
架构基类,实现了 `IArchitecture` 接口,提供完整的架构功能实现。
|
||||||
|
|
||||||
**构造函数参数:**
|
**构造函数参数:**
|
||||||
```csharp
|
```csharp
|
||||||
public abstract class Architecture(
|
public abstract class Architecture(
|
||||||
IArchitectureConfiguration? configuration = null,
|
IArchitectureConfiguration? configuration = null,
|
||||||
@ -90,17 +92,19 @@ public abstract class Architecture(
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
**特性:**
|
**特性:**
|
||||||
|
|
||||||
- **阶段式生命周期管理**:支持多个架构阶段(
|
- **阶段式生命周期管理**
|
||||||
BeforeUtilityInit、AfterUtilityInit、BeforeModelInit、AfterModelInit、BeforeSystemInit、AfterSystemInit、Ready、Destroying、Destroyed)
|
:支持多个架构阶段(BeforeUtilityInit、AfterUtilityInit、BeforeModelInit、AfterModelInit、BeforeSystemInit、AfterSystemInit、Ready、FailedInitialization、Destroying、Destroyed)
|
||||||
- **模块安装系统**:支持通过 `InstallModule` 扩展架构功能
|
- **模块安装系统**:支持通过 `InstallModule` 扩展架构功能
|
||||||
- **异步初始化**:支持同步和异步两种初始化方式
|
- **异步初始化**:支持同步和异步两种初始化方式
|
||||||
- **IoC 容器集成**:内置依赖注入容器
|
- **IoC 容器集成**:内置依赖注入容器
|
||||||
- **事件系统集成**:集成类型化事件系统
|
- **事件系统集成**:集成类型化事件系统
|
||||||
- **与平台无关**:Core 模块不依赖 Godot,可以在任何 .NET 环境中使用
|
- **与平台无关**:Core 模块不依赖 Godot,可以在任何 .NET 环境中使用
|
||||||
|
- **严格的阶段验证**:可配置的阶段转换验证机制
|
||||||
|
- **组件生命周期管理**:自动管理组件的初始化和销毁
|
||||||
|
|
||||||
**架构阶段:**
|
**架构阶段:**
|
||||||
```csharp
|
```csharp
|
||||||
public enum ArchitecturePhase
|
public enum ArchitecturePhase
|
||||||
{
|
{
|
||||||
@ -118,28 +122,29 @@ public enum ArchitecturePhase
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**初始化流程:**
|
**初始化流程:**
|
||||||
|
|
||||||
1. 创建架构实例(传入配置或使用默认配置)
|
1. 创建架构实例(传入配置或使用默认配置)
|
||||||
2. 调用用户自定义的 `Init()` 方法
|
2. 初始化基础上下文和日志系统
|
||||||
3. 初始化上下文工具(Context Utility)
|
3. 调用用户自定义的 `Init()` 方法
|
||||||
4. 初始化所有注册的 Model
|
4. 按顺序初始化组件:
|
||||||
5. 初始化所有注册的 System
|
- 工具初始化(BeforeUtilityInit → AfterUtilityInit)
|
||||||
6. 冻结 IOC 容器
|
- 模型初始化(BeforeModelInit → AfterModelInit)
|
||||||
7. 进入 Ready 阶段
|
- 系统初始化(BeforeSystemInit → AfterSystemInit)
|
||||||
|
5. 冻结 IOC 容器
|
||||||
|
6. 进入 Ready 阶段
|
||||||
|
|
||||||
**销毁流程:**
|
**销毁流程:**
|
||||||
|
|
||||||
1. 进入 Destroying 阶段
|
1. 进入 Destroying 阶段
|
||||||
2. 发送 `ArchitectureDestroyingEvent` 事件
|
2. 按注册逆序销毁所有实现了 `IDisposable` 的组件
|
||||||
3. 销毁所有 System
|
3. 进入 Destroyed 阶段
|
||||||
4. 进入 Destroyed 阶段
|
4. 清理所有资源
|
||||||
5. 发送 `ArchitectureDestroyedEvent` 事件
|
|
||||||
|
|
||||||
**使用示例:**
|
**使用示例:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// 1. 定义你的架构(继承 Architecture 基类)
|
// 1. 定义你的架构(继承 Architecture 基类)
|
||||||
public class GameArchitecture : Architecture
|
public class GameArchitecture : Architecture
|
||||||
{
|
{
|
||||||
protected override void Init()
|
protected override void Init()
|
||||||
@ -166,31 +171,28 @@ architecture.Initialize();
|
|||||||
// var architecture = new GameArchitecture();
|
// var architecture = new GameArchitecture();
|
||||||
// await architecture.InitializeAsync();
|
// await architecture.InitializeAsync();
|
||||||
|
|
||||||
// 3. 通过依赖注入使用架构
|
// 3. 等待架构就绪
|
||||||
// 在 Controller 或其他组件中注入架构实例
|
await architecture.WaitUntilReadyAsync();
|
||||||
|
|
||||||
|
// 4. 通过依赖注入使用架构
|
||||||
|
// 在 Controller 或其他组件中获取架构实例
|
||||||
public class GameController : IController
|
public class GameController : IController
|
||||||
{
|
{
|
||||||
private readonly IArchitecture _architecture;
|
public IArchitecture GetArchitecture() => GameArchitecture.Interface;
|
||||||
|
|
||||||
// 通过构造函数注入架构
|
|
||||||
public GameController(IArchitecture architecture)
|
|
||||||
{
|
|
||||||
_architecture = architecture;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
// 获取 Model
|
// 获取 Model
|
||||||
var playerModel = _architecture.GetModel<PlayerModel>();
|
var playerModel = this.GetModel<PlayerModel>();
|
||||||
|
|
||||||
// 发送命令
|
// 发送命令
|
||||||
_architecture.SendCommand(new StartGameCommand());
|
this.SendCommand(new StartGameCommand());
|
||||||
|
|
||||||
// 发送查询
|
// 发送查询
|
||||||
var score = _architecture.SendQuery(new GetScoreQuery());
|
var score = this.SendQuery(new GetScoreQuery());
|
||||||
|
|
||||||
// 注册事件
|
// 注册事件
|
||||||
_architecture.RegisterEvent<PlayerDiedEvent>(OnPlayerDied);
|
this.RegisterEvent<PlayerDiedEvent>(OnPlayerDied);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPlayerDied(PlayerDiedEvent e)
|
private void OnPlayerDied(PlayerDiedEvent e)
|
||||||
@ -206,52 +208,73 @@ public class GameController : IController
|
|||||||
|
|
||||||
**Initialize()**
|
**Initialize()**
|
||||||
|
|
||||||
同步初始化方法,阻塞当前线程直到初始化完成。
|
同步初始化方法,阻塞当前线程直到初始化完成。
|
||||||
```csharp
|
```csharp
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
```
|
```
|
||||||
|
|
||||||
使用示例:
|
**特点:**
|
||||||
|
|
||||||
|
- 阻塞式初始化
|
||||||
|
- 适用于简单场景或控制台应用
|
||||||
|
- 初始化失败时抛出异常并进入 `FailedInitialization` 阶段
|
||||||
|
|
||||||
|
使用示例:
|
||||||
```csharp
|
```csharp
|
||||||
var architecture = new GameArchitecture();
|
var architecture = new GameArchitecture();
|
||||||
architecture.Initialize(); // 阻塞等待初始化完成
|
architecture.Initialize(); // 阻塞等待初始化完成
|
||||||
```
|
```
|
||||||
|
|
||||||
异常处理: 如果初始化过程中发生异常,架构会进入 `FailedInitialization` 阶段并发送 `ArchitectureFailedInitializationEvent`
|
异常处理:如果初始化过程中发生异常,架构会进入 `FailedInitialization` 阶段。
|
||||||
事件。
|
|
||||||
|
|
||||||
**InitializeAsync()**
|
**InitializeAsync()**
|
||||||
|
|
||||||
异步初始化方法,返回 Task 以便调用者可以等待初始化完成。
|
异步初始化方法,返回 Task 以便调用者可以等待初始化完成。
|
||||||
```csharp
|
```csharp
|
||||||
public async Task InitializeAsync()
|
public async Task InitializeAsync()
|
||||||
```
|
```
|
||||||
|
|
||||||
使用示例:
|
**特点:**
|
||||||
|
|
||||||
|
- 非阻塞式初始化
|
||||||
|
- 支持异步组件初始化
|
||||||
|
- 适用于需要异步加载资源的场景
|
||||||
|
- 初始化失败时抛出异常并进入 `FailedInitialization` 阶段
|
||||||
|
|
||||||
|
使用示例:
|
||||||
```csharp
|
```csharp
|
||||||
var architecture = new GameArchitecture();
|
var architecture = new GameArchitecture();
|
||||||
await architecture.InitializeAsync(); // 异步等待初始化完成
|
await architecture.InitializeAsync(); // 异步等待初始化完成
|
||||||
```
|
```
|
||||||
|
|
||||||
优势:
|
优势:
|
||||||
- 支持异步初始化 Model 和 System
|
- 支持异步初始化 Model 和 System
|
||||||
- 可以利用异步 I/O 操作(如异步加载数据)
|
- 可以利用异步 I/O 操作(如异步加载数据)
|
||||||
- 提高初始化性能
|
- 提高初始化性能
|
||||||
|
- 不会阻塞主线程
|
||||||
|
|
||||||
#### 模块管理
|
#### 模块管理
|
||||||
|
|
||||||
**InstallModule(IArchitectureModule module)**
|
**InstallModule(IArchitectureModule module)**
|
||||||
|
|
||||||
安装架构模块,用于扩展架构功能。
|
安装架构模块,用于扩展架构功能。
|
||||||
```csharp
|
```csharp
|
||||||
public void InstallModule(IArchitectureModule module)
|
public IArchitectureModule InstallModule(IArchitectureModule module)
|
||||||
```
|
```
|
||||||
|
|
||||||
参数:
|
**返回值:** 返回安装的模块实例
|
||||||
|
|
||||||
- `module`:要安装的模块实例
|
**特点:**
|
||||||
|
|
||||||
使用示例:
|
- 模块安装时会自动注册生命周期钩子
|
||||||
|
- 模块可以注册额外的组件到架构中
|
||||||
|
- 只能在架构进入 Ready 阶段之前安装模块
|
||||||
|
|
||||||
|
参数:
|
||||||
|
|
||||||
|
- `module`:要安装的模块实例
|
||||||
|
|
||||||
|
使用示例:
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// 定义模块
|
// 定义模块
|
||||||
@ -267,23 +290,31 @@ public class NetworkModule : IArchitectureModule
|
|||||||
|
|
||||||
// 安装模块
|
// 安装模块
|
||||||
var architecture = new GameArchitecture();
|
var architecture = new GameArchitecture();
|
||||||
architecture.InstallModule(new NetworkModule());
|
var installedModule = architecture.InstallModule(new NetworkModule());
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 生命周期钩子
|
#### 生命周期钩子
|
||||||
|
|
||||||
**RegisterLifecycleHook(IArchitectureLifecycle hook)**
|
**RegisterLifecycleHook(IArchitectureLifecycle hook)**
|
||||||
|
|
||||||
注册生命周期钩子,用于在架构阶段变化时执行自定义逻辑。
|
注册生命周期钩子,用于在架构阶段变化时执行自定义逻辑。
|
||||||
```csharp
|
```csharp
|
||||||
public void RegisterLifecycleHook(IArchitectureLifecycle hook)
|
public IArchitectureLifecycle RegisterLifecycleHook(IArchitectureLifecycle hook)
|
||||||
```
|
```
|
||||||
|
|
||||||
参数:
|
**返回值:** 返回注册的生命周期钩子实例
|
||||||
|
|
||||||
- `hook`:生命周期钩子实例
|
**特点:**
|
||||||
|
|
||||||
使用示例:
|
- 生命周期钩子可以监听所有架构阶段变化
|
||||||
|
- 只能在架构进入 Ready 阶段之前注册
|
||||||
|
- 架构会按注册顺序通知所有钩子
|
||||||
|
|
||||||
|
参数:
|
||||||
|
|
||||||
|
- `hook`:生命周期钩子实例
|
||||||
|
|
||||||
|
使用示例:
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// 定义生命周期钩子
|
// 定义生命周期钩子
|
||||||
@ -308,11 +339,11 @@ public class PerformanceMonitorHook : IArchitectureLifecycle
|
|||||||
|
|
||||||
// 注册生命周期钩子
|
// 注册生命周期钩子
|
||||||
var architecture = new GameArchitecture();
|
var architecture = new GameArchitecture();
|
||||||
architecture.RegisterLifecycleHook(new PerformanceMonitorHook());
|
var registeredHook = architecture.RegisterLifecycleHook(new PerformanceMonitorHook());
|
||||||
architecture.Initialize();
|
architecture.Initialize();
|
||||||
```
|
```
|
||||||
|
|
||||||
**注意:** 生命周期钩子只能在架构进入 Ready 阶段之前注册。
|
**注意:** 生命周期钩子只能在架构进入 Ready 阶段之前注册。
|
||||||
|
|
||||||
#### 属性
|
#### 属性
|
||||||
|
|
||||||
@ -320,10 +351,16 @@ architecture.Initialize();
|
|||||||
|
|
||||||
获取当前架构的阶段。
|
获取当前架构的阶段。
|
||||||
```csharp
|
```csharp
|
||||||
public ArchitecturePhase CurrentPhase { get; }
|
public ArchitecturePhase CurrentPhase { get; private set; }
|
||||||
```
|
```
|
||||||
|
|
||||||
使用示例:
|
**特点:**
|
||||||
|
|
||||||
|
- 只读属性,外部无法直接修改
|
||||||
|
- 实时反映架构的当前状态
|
||||||
|
- 可用于条件判断和状态检查
|
||||||
|
|
||||||
|
使用示例:
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var architecture = new GameArchitecture();
|
var architecture = new GameArchitecture();
|
||||||
@ -347,12 +384,18 @@ await Task.Run(async () =>
|
|||||||
|
|
||||||
**Context**
|
**Context**
|
||||||
|
|
||||||
获取架构上下文,提供对架构服务的访问。
|
获取架构上下文,提供对架构服务的访问。
|
||||||
```csharp
|
```csharp
|
||||||
public IArchitectureContext Context { get; }
|
public IArchitectureContext Context { get; }
|
||||||
```
|
```
|
||||||
|
|
||||||
使用示例:
|
**特点:**
|
||||||
|
|
||||||
|
- 提供对架构核心服务的访问
|
||||||
|
- 包含事件总线、命令总线、查询总线等
|
||||||
|
- 是架构内部服务的统一入口
|
||||||
|
|
||||||
|
使用示例:
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// 通过 Context 访问服务
|
// 通过 Context 访问服务
|
||||||
@ -367,7 +410,14 @@ var environment = context.Environment;
|
|||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// 1. 使用自定义配置
|
// 1. 使用自定义配置
|
||||||
var config = new ArchitectureConfiguration();
|
var config = new ArchitectureConfiguration
|
||||||
|
{
|
||||||
|
ArchitectureProperties = new ArchitectureProperties
|
||||||
|
{
|
||||||
|
StrictPhaseValidation = true, // 启用严格阶段验证
|
||||||
|
AllowLateRegistration = false // 禁止就绪后注册组件
|
||||||
|
}
|
||||||
|
};
|
||||||
var architecture = new GameArchitecture(configuration: config);
|
var architecture = new GameArchitecture(configuration: config);
|
||||||
|
|
||||||
// 2. 模块安装
|
// 2. 模块安装
|
||||||
@ -382,10 +432,10 @@ public class GamePhaseListener : IArchitecturePhaseAware
|
|||||||
switch (phase)
|
switch (phase)
|
||||||
{
|
{
|
||||||
case ArchitecturePhase.Ready:
|
case ArchitecturePhase.Ready:
|
||||||
GD.Print("架构已就绪,可以开始游戏了");
|
Console.WriteLine("架构已就绪,可以开始游戏了");
|
||||||
break;
|
break;
|
||||||
case ArchitecturePhase.Destroying:
|
case ArchitecturePhase.Destroying:
|
||||||
GD.Print("架构正在销毁");
|
Console.WriteLine("架构正在销毁");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -396,24 +446,57 @@ public class LifecycleHook : IArchitectureLifecycle
|
|||||||
{
|
{
|
||||||
public void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
|
public void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
|
||||||
{
|
{
|
||||||
GD.Print($"架构阶段变化: {phase}");
|
Console.WriteLine($"架构阶段变化: {phase}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 5. 等待架构就绪
|
||||||
|
public async Task WaitForArchitectureReady()
|
||||||
|
{
|
||||||
|
var architecture = new GameArchitecture();
|
||||||
|
var initTask = architecture.InitializeAsync();
|
||||||
|
|
||||||
|
// 可以在其他地方等待架构就绪
|
||||||
|
await architecture.WaitUntilReadyAsync();
|
||||||
|
Console.WriteLine("架构已就绪");
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### ArchitectureConfiguration 架构配置类
|
### ArchitectureConfiguration 架构配置类
|
||||||
|
|
||||||
架构配置类,用于配置架构的行为。
|
架构配置类,用于配置架构的行为。
|
||||||
|
|
||||||
**使用示例:**
|
**主要配置项:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class ArchitectureConfiguration : IArchitectureConfiguration
|
||||||
|
{
|
||||||
|
public IArchitectureProperties ArchitectureProperties { get; set; } = new ArchitectureProperties();
|
||||||
|
public IEnvironmentProperties EnvironmentProperties { get; set; } = new EnvironmentProperties();
|
||||||
|
public ILoggerProperties LoggerProperties { get; set; } = new LoggerProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ArchitectureProperties
|
||||||
|
{
|
||||||
|
public bool StrictPhaseValidation { get; set; } = false; // 严格阶段验证
|
||||||
|
public bool AllowLateRegistration { get; set; } = true; // 允许延迟注册
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var config = new ArchitectureConfiguration
|
var config = new ArchitectureConfiguration
|
||||||
{
|
{
|
||||||
// 严格阶段验证
|
ArchitectureProperties = new ArchitectureProperties
|
||||||
StrictPhaseValidation = true,
|
{
|
||||||
// 允许延迟注册
|
StrictPhaseValidation = true, // 启用严格阶段验证
|
||||||
AllowLateRegistration = false
|
AllowLateRegistration = false // 禁止就绪后注册组件
|
||||||
|
},
|
||||||
|
LoggerProperties = new LoggerProperties
|
||||||
|
{
|
||||||
|
LoggerFactoryProvider = new ConsoleLoggerFactoryProvider() // 自定义日志工厂
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var architecture = new GameArchitecture(configuration: config);
|
var architecture = new GameArchitecture(configuration: config);
|
||||||
@ -421,15 +504,34 @@ var architecture = new GameArchitecture(configuration: config);
|
|||||||
|
|
||||||
### ArchitectureServices 架构服务类
|
### ArchitectureServices 架构服务类
|
||||||
|
|
||||||
架构服务类,管理命令总线、查询总线、IOC容器和类型事件系统。
|
架构服务类,管理命令总线、查询总线、IOC容器和类型事件系统。
|
||||||
|
|
||||||
|
**核心服务:**
|
||||||
|
|
||||||
|
- `IIocContainer Container`:依赖注入容器
|
||||||
|
- `IEventBus EventBus`:事件总线
|
||||||
|
- `ICommandBus CommandBus`:命令总线
|
||||||
|
- `IQueryBus QueryBus`:查询总线
|
||||||
|
|
||||||
### ArchitectureContext 架构上下文类
|
### ArchitectureContext 架构上下文类
|
||||||
|
|
||||||
架构上下文类,提供对架构服务的访问。
|
架构上下文类,提供对架构服务的访问。
|
||||||
|
|
||||||
|
**功能:**
|
||||||
|
|
||||||
|
- 统一访问架构核心服务
|
||||||
|
- 管理服务实例的生命周期
|
||||||
|
- 提供服务解析功能
|
||||||
|
|
||||||
### GameContext 游戏上下文类
|
### GameContext 游戏上下文类
|
||||||
|
|
||||||
游戏上下文类,管理架构上下文与类型的绑定关系。
|
游戏上下文类,管理架构上下文与类型的绑定关系。
|
||||||
|
|
||||||
|
**功能:**
|
||||||
|
|
||||||
|
- 维护架构类型与上下文实例的映射
|
||||||
|
- 提供全局上下文访问
|
||||||
|
- 支持多架构实例管理
|
||||||
|
|
||||||
## 设计模式
|
## 设计模式
|
||||||
|
|
||||||
@ -459,20 +561,31 @@ var architecture = new GameArchitecture(configuration: config);
|
|||||||
|
|
||||||
### 7. 组合优于继承
|
### 7. 组合优于继承
|
||||||
|
|
||||||
通过接口组合获得不同能力,而不是深层继承链。
|
通过接口组合获得不同能力,而不是深层继承链。
|
||||||
|
|
||||||
|
### 8. 模块化设计
|
||||||
|
|
||||||
|
通过 `IArchitectureModule` 实现架构的可扩展性。
|
||||||
|
|
||||||
|
### 9. 工厂模式
|
||||||
|
|
||||||
|
通过配置对象和工厂方法创建架构实例。
|
||||||
|
|
||||||
## 最佳实践
|
## 最佳实践
|
||||||
|
|
||||||
1. **保持架构类简洁**:只在 `Init()` 中注册组件,不要包含业务逻辑
|
1. **保持架构类简洁**:只在 `Init()` 中注册组件,不要包含业务逻辑
|
||||||
2. **合理划分职责**:
|
2. **合理划分职责**:
|
||||||
- Model:数据和状态
|
- Model:数据和状态
|
||||||
- System:业务逻辑和规则
|
- System:业务逻辑和规则
|
||||||
- Utility:无状态的工具方法
|
- Utility:无状态的工具方法
|
||||||
3. **使用依赖注入**:通过构造函数注入架构实例,便于测试
|
3. **使用依赖注入**:通过构造函数注入架构实例,便于测试
|
||||||
4. **事件命名规范**:使用过去式命名事件类,如 `PlayerDiedEvent`
|
4. **事件命名规范**:使用过去式命名事件类,如 `PlayerDiedEvent`
|
||||||
5. **避免循环依赖**:System 不应直接引用 System,应通过事件通信
|
5. **避免循环依赖**:System 不应直接引用 System,应通过事件通信
|
||||||
6. **使用模块扩展**:通过 `IArchitectureModule` 实现架构的可扩展性
|
6. **使用模块扩展**:通过 `IArchitectureModule` 实现架构的可扩展性
|
||||||
7. **Core 模块与平台解耦**:GFramework.Core 不包含 Godot 相关代码,Godot 集成在单独模块中
|
7. **Core 模块与平台解耦**:GFramework.Core 不包含 Godot 相关代码,Godot 集成在单独模块中
|
||||||
|
8. **合理配置阶段验证**:根据项目需求配置 `StrictPhaseValidation` 和 `AllowLateRegistration`
|
||||||
|
9. **及时处理初始化异常**:捕获并处理架构初始化过程中的异常
|
||||||
|
10. **使用异步初始化**:对于需要加载大量资源的场景,优先使用 `InitializeAsync()`
|
||||||
|
|
||||||
## 相关包
|
## 相关包
|
||||||
|
|
||||||
@ -483,8 +596,11 @@ var architecture = new GameArchitecture(configuration: config);
|
|||||||
- **model** - 数据模型
|
- **model** - 数据模型
|
||||||
- **system** - 业务系统
|
- **system** - 业务系统
|
||||||
- **utility** - 工具类
|
- **utility** - 工具类
|
||||||
- **GFramework.Godot** - Godot 特定集成(GodotNode 扩展、GodotLogger 等)
|
- **GFramework.Godot** - Godot 特定集成(GodotNode 扩展、GodotLogger 等)
|
||||||
|
- **extensions** - 扩展方法
|
||||||
|
- **logging** - 日志系统
|
||||||
|
- **environment** - 环境管理
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**许可证**: Apache 2.0
|
**许可证**:Apache 2.0
|
||||||
@ -4,9 +4,11 @@
|
|||||||
|
|
||||||
Command 包实现了命令模式(Command Pattern),用于封装用户操作和业务逻辑。通过命令模式,可以将请求封装为对象,实现操作的参数化、队列化、日志记录、撤销等功能。
|
Command 包实现了命令模式(Command Pattern),用于封装用户操作和业务逻辑。通过命令模式,可以将请求封装为对象,实现操作的参数化、队列化、日志记录、撤销等功能。
|
||||||
|
|
||||||
|
命令系统是 GFramework CQRS 架构的重要组成部分,与事件系统和查询系统协同工作,实现完整的业务逻辑处理流程。
|
||||||
|
|
||||||
## 核心接口
|
## 核心接口
|
||||||
|
|
||||||
### 1. [`ICommand`](./command.md)
|
### ICommand
|
||||||
|
|
||||||
无返回值命令接口,定义了命令的基本契约。
|
无返回值命令接口,定义了命令的基本契约。
|
||||||
|
|
||||||
@ -16,7 +18,7 @@ Command 包实现了命令模式(Command Pattern),用于封装用户操作
|
|||||||
void Execute(); // 执行命令
|
void Execute(); // 执行命令
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. [`ICommand<TResult>`](./command.md)
|
### ICommand`<TResult>`
|
||||||
|
|
||||||
带返回值的命令接口,用于需要返回执行结果的命令。
|
带返回值的命令接口,用于需要返回执行结果的命令。
|
||||||
|
|
||||||
@ -28,37 +30,41 @@ TResult Execute(); // 执行命令并返回结果
|
|||||||
|
|
||||||
## 核心类
|
## 核心类
|
||||||
|
|
||||||
### 1. [`AbstractCommand<TInput>`](./command.md)
|
### AbstractCommand
|
||||||
|
|
||||||
无返回值命令的抽象基类,提供了命令的基础实现。它继承自 [ContextAwareBase](./rule.md)
|
无返回值命令的抽象基类,提供了命令的基础实现。它继承自 ContextAwareBase,具有上下文感知能力。
|
||||||
,具有上下文感知能力。
|
|
||||||
|
**核心方法:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
void ICommand.Execute(); // 实现 ICommand 接口
|
||||||
|
protected abstract void OnExecute(); // 抽象执行方法,由子类实现
|
||||||
|
```
|
||||||
|
|
||||||
**使用示例:**
|
**使用示例:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// 定义一个命令输入参数
|
|
||||||
public struct StartGameCommandInput : ICommandInput
|
|
||||||
{
|
|
||||||
public int LevelId { get; set; }
|
|
||||||
public string PlayerName { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// 定义一个开始游戏的命令
|
// 定义一个开始游戏的命令
|
||||||
public class StartGameCommand : AbstractCommand<StartGameCommandInput>
|
public class StartGameCommand : AbstractCommand
|
||||||
{
|
{
|
||||||
public StartGameCommand(StartGameCommandInput input) : base(input)
|
private readonly int _levelId;
|
||||||
|
private readonly string _playerName;
|
||||||
|
|
||||||
|
public StartGameCommand(int levelId, string playerName)
|
||||||
{
|
{
|
||||||
|
_levelId = levelId;
|
||||||
|
_playerName = playerName;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnExecute(StartGameCommandInput input)
|
protected override void OnExecute()
|
||||||
{
|
{
|
||||||
// 获取需要的模型
|
// 获取需要的模型
|
||||||
var playerModel = this.GetModel<PlayerModel>();
|
var playerModel = this.GetModel<PlayerModel>();
|
||||||
var gameModel = this.GetModel<GameModel>();
|
var gameModel = this.GetModel<GameModel>();
|
||||||
|
|
||||||
// 执行业务逻辑
|
// 执行业务逻辑
|
||||||
playerModel.PlayerName.Value = input.PlayerName;
|
playerModel.PlayerName.Value = _playerName;
|
||||||
gameModel.CurrentLevel.Value = input.LevelId;
|
gameModel.CurrentLevel.Value = _levelId;
|
||||||
gameModel.GameState.Value = GameState.Playing;
|
gameModel.GameState.Value = GameState.Playing;
|
||||||
|
|
||||||
// 发送事件通知其他模块
|
// 发送事件通知其他模块
|
||||||
@ -74,43 +80,44 @@ public class GameController : IController
|
|||||||
public void OnStartButtonClicked()
|
public void OnStartButtonClicked()
|
||||||
{
|
{
|
||||||
// 发送命令实例
|
// 发送命令实例
|
||||||
this.SendCommand(new StartGameCommand(new StartGameCommandInput
|
this.SendCommand(new StartGameCommand(1, "Player1"));
|
||||||
{
|
|
||||||
LevelId = 1,
|
|
||||||
PlayerName = "Player1"
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. [`AbstractCommand<TInput, TResult>`](./command.md)
|
### AbstractCommandWithResult`<TResult>`
|
||||||
|
|
||||||
带返回值命令的抽象基类,同样继承自 [ContextAwareBase](./rule.md)。
|
带返回值命令的抽象基类,同样继承自 ContextAwareBase。
|
||||||
|
|
||||||
|
**核心方法:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
TResult ICommand<TResult>.Execute(); // 实现 ICommand<TResult> 接口
|
||||||
|
protected abstract TResult OnExecute(); // 抽象执行方法,由子类实现
|
||||||
|
```
|
||||||
|
|
||||||
**使用示例:**
|
**使用示例:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// 定义一个计算伤害的命令输入
|
|
||||||
public struct CalculateDamageCommandInput : ICommandInput
|
|
||||||
{
|
|
||||||
public int AttackerAttackPower { get; set; }
|
|
||||||
public int DefenderDefense { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// 定义一个计算伤害的命令
|
// 定义一个计算伤害的命令
|
||||||
public class CalculateDamageCommand : AbstractCommand<CalculateDamageCommandInput, int>
|
public class CalculateDamageCommand : AbstractCommandWithResult<int>
|
||||||
{
|
{
|
||||||
public CalculateDamageCommand(CalculateDamageCommandInput input) : base(input)
|
private readonly int _attackerAttackPower;
|
||||||
|
private readonly int _defenderDefense;
|
||||||
|
|
||||||
|
public CalculateDamageCommand(int attackerAttackPower, int defenderDefense)
|
||||||
{
|
{
|
||||||
|
_attackerAttackPower = attackerAttackPower;
|
||||||
|
_defenderDefense = defenderDefense;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override int OnExecute(CalculateDamageCommandInput input)
|
protected override int OnExecute()
|
||||||
{
|
{
|
||||||
// 获取游戏配置
|
// 获取游戏配置
|
||||||
var config = this.GetModel<GameConfigModel>();
|
var config = this.GetModel<GameConfigModel>();
|
||||||
|
|
||||||
// 计算最终伤害
|
// 计算最终伤害
|
||||||
var baseDamage = input.AttackerAttackPower - input.DefenderDefense;
|
var baseDamage = _attackerAttackPower - _defenderDefense;
|
||||||
var finalDamage = Math.Max(1, baseDamage * config.DamageMultiplier);
|
var finalDamage = Math.Max(1, baseDamage * config.DamageMultiplier);
|
||||||
|
|
||||||
return (int)finalDamage;
|
return (int)finalDamage;
|
||||||
@ -125,11 +132,10 @@ public class CombatSystem : AbstractSystem
|
|||||||
public void Attack(Character attacker, Character defender)
|
public void Attack(Character attacker, Character defender)
|
||||||
{
|
{
|
||||||
// 发送命令并获取返回值
|
// 发送命令并获取返回值
|
||||||
var damage = this.SendCommand(new CalculateDamageCommand(new CalculateDamageCommandInput
|
var damage = this.SendCommand(new CalculateDamageCommand(
|
||||||
{
|
attacker.AttackPower,
|
||||||
AttackerAttackPower = attacker.AttackPower,
|
defender.Defense
|
||||||
DefenderDefense = defender.Defense
|
));
|
||||||
}));
|
|
||||||
|
|
||||||
// 应用伤害
|
// 应用伤害
|
||||||
defender.Health -= damage;
|
defender.Health -= damage;
|
||||||
@ -147,6 +153,12 @@ public class CombatSystem : AbstractSystem
|
|||||||
3. **返回结果**:对于带返回值的命令,返回执行结果
|
3. **返回结果**:对于带返回值的命令,返回执行结果
|
||||||
4. **命令销毁**:命令执行完毕后可以被垃圾回收
|
4. **命令销毁**:命令执行完毕后可以被垃圾回收
|
||||||
|
|
||||||
|
**注意事项:**
|
||||||
|
|
||||||
|
- 命令应该是无状态的,执行完即可丢弃
|
||||||
|
- 避免在命令中保存长期引用
|
||||||
|
- 命令执行应该是原子操作
|
||||||
|
|
||||||
## CommandBus - 命令总线
|
## CommandBus - 命令总线
|
||||||
|
|
||||||
### 功能说明
|
### 功能说明
|
||||||
@ -156,64 +168,122 @@ public class CombatSystem : AbstractSystem
|
|||||||
**主要方法:**
|
**主要方法:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
void Send(ICommand command); // 发送无返回值命令
|
void Send(ICommand command); // 发送无返回值命令
|
||||||
TResult Send<TResult>(ICommand<TResult> command); // 发送带返回值命令
|
TResult Send<TResult>(ICommand<TResult> command); // 发送带返回值命令
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**特点:**
|
||||||
|
|
||||||
|
- 统一的命令执行入口
|
||||||
|
- 支持同步命令执行
|
||||||
|
- 与架构上下文集成
|
||||||
|
|
||||||
### 使用示例
|
### 使用示例
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var commandBus = new CommandBus();
|
// 通过架构获取命令总线
|
||||||
|
var commandBus = architecture.Context.CommandBus;
|
||||||
|
|
||||||
// 发送无返回值命令
|
// 发送无返回值命令
|
||||||
commandBus.Send(new StartGameCommand(new StartGameCommandInput()));
|
commandBus.Send(new StartGameCommand(1, "Player1"));
|
||||||
|
|
||||||
// 发送带返回值命令
|
// 发送带返回值命令
|
||||||
var result = commandBus.Send(new CalculateDamageCommand(new CalculateDamageCommandInput()));
|
var damage = commandBus.Send(new CalculateDamageCommand(100, 50));
|
||||||
```
|
```
|
||||||
|
|
||||||
## EmptyCommandInput - 空命令输入
|
## 命令基类变体
|
||||||
|
|
||||||
当命令不需要输入参数时,可以使用 `EmptyCommandInput` 类:
|
框架提供了多种命令基类以满足不同需求:
|
||||||
|
|
||||||
|
### AbstractCommand
|
||||||
|
|
||||||
|
最基础的无返回值命令类
|
||||||
|
|
||||||
|
### AbstractCommandWithResult`<TResult>`
|
||||||
|
|
||||||
|
带返回值的命令基类
|
||||||
|
|
||||||
|
### AbstractCommandWithInput`<TInput>`
|
||||||
|
|
||||||
|
带输入参数的无返回值命令类
|
||||||
|
|
||||||
|
### AbstractCommandWithInputAndResult`<TInput, TResult>`
|
||||||
|
|
||||||
|
既带输入参数又带返回值的命令类
|
||||||
|
|
||||||
|
### AbstractAsyncCommand
|
||||||
|
|
||||||
|
支持异步执行的命令基类
|
||||||
|
|
||||||
|
### AbstractAsyncCommandWithResult`<TResult>`
|
||||||
|
|
||||||
|
支持异步执行的带返回值命令基类
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public class SimpleActionCommand : AbstractCommand<EmptyCommandInput>
|
// 异步命令示例
|
||||||
|
public class LoadSaveDataCommand : AbstractAsyncCommandWithResult<SaveData>
|
||||||
{
|
{
|
||||||
public SimpleActionCommand(EmptyCommandInput input) : base(input)
|
private readonly string _saveSlot;
|
||||||
|
|
||||||
|
public LoadSaveDataCommand(string saveSlot)
|
||||||
{
|
{
|
||||||
|
_saveSlot = saveSlot;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnExecute(EmptyCommandInput input)
|
protected override async Task<SaveData> OnExecuteAsync()
|
||||||
{
|
{
|
||||||
// 执行简单操作,无需额外参数
|
var storage = this.GetUtility<IStorageUtility>();
|
||||||
this.SendEvent(new SimpleActionEvent());
|
return await storage.LoadSaveDataAsync(_saveSlot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 命令处理器执行
|
||||||
|
|
||||||
|
所有发送给命令总线的命令最终都会通过 `CommandExecutor` 来执行:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class CommandExecutor
|
||||||
|
{
|
||||||
|
public static void Execute(ICommand command)
|
||||||
|
{
|
||||||
|
command.Execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult Execute<TResult>(ICommand<TResult> command)
|
||||||
|
{
|
||||||
|
return command.Execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**特点:**
|
||||||
|
|
||||||
|
- 提供统一的命令执行机制
|
||||||
|
- 支持同步和异步命令执行
|
||||||
|
- 可以扩展添加中间件逻辑
|
||||||
|
|
||||||
## 使用场景
|
## 使用场景
|
||||||
|
|
||||||
### 1. 用户交互操作
|
### 1. 用户交互操作
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public struct SaveGameCommandInput : ICommandInput
|
public class SaveGameCommand : AbstractCommand
|
||||||
{
|
{
|
||||||
public string SaveSlot { get; set; }
|
private readonly string _saveSlot;
|
||||||
}
|
|
||||||
|
|
||||||
public class SaveGameCommand : AbstractCommand<SaveGameCommandInput>
|
public SaveGameCommand(string saveSlot)
|
||||||
{
|
|
||||||
public SaveGameCommand(SaveGameCommandInput input) : base(input)
|
|
||||||
{
|
{
|
||||||
|
_saveSlot = saveSlot;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnExecute(SaveGameCommandInput input)
|
protected override void OnExecute()
|
||||||
{
|
{
|
||||||
var saveSystem = this.GetSystem<SaveSystem>();
|
var saveSystem = this.GetSystem<SaveSystem>();
|
||||||
var playerModel = this.GetModel<PlayerModel>();
|
var playerModel = this.GetModel<PlayerModel>();
|
||||||
|
|
||||||
saveSystem.SavePlayerData(playerModel, input.SaveSlot);
|
saveSystem.SavePlayerData(playerModel, _saveSlot);
|
||||||
this.SendEvent(new GameSavedEvent(input.SaveSlot));
|
this.SendEvent(new GameSavedEvent(_saveSlot));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -221,18 +291,16 @@ public class SaveGameCommand : AbstractCommand<SaveGameCommandInput>
|
|||||||
### 2. 业务流程控制
|
### 2. 业务流程控制
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public struct LoadLevelCommandInput : ICommandInput
|
public class LoadLevelCommand : AbstractCommand
|
||||||
{
|
{
|
||||||
public int LevelId { get; set; }
|
private readonly int _levelId;
|
||||||
}
|
|
||||||
|
|
||||||
public class LoadLevelCommand : AbstractCommand<LoadLevelCommandInput>
|
public LoadLevelCommand(int levelId)
|
||||||
{
|
|
||||||
public LoadLevelCommand(LoadLevelCommandInput input) : base(input)
|
|
||||||
{
|
{
|
||||||
|
_levelId = levelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnExecute(LoadLevelCommandInput input)
|
protected override void OnExecute()
|
||||||
{
|
{
|
||||||
var levelSystem = this.GetSystem<LevelSystem>();
|
var levelSystem = this.GetSystem<LevelSystem>();
|
||||||
var uiSystem = this.GetSystem<UISystem>();
|
var uiSystem = this.GetSystem<UISystem>();
|
||||||
@ -241,10 +309,10 @@ public class LoadLevelCommand : AbstractCommand<LoadLevelCommandInput>
|
|||||||
uiSystem.ShowLoadingScreen();
|
uiSystem.ShowLoadingScreen();
|
||||||
|
|
||||||
// 加载关卡
|
// 加载关卡
|
||||||
levelSystem.LoadLevel(input.LevelId);
|
levelSystem.LoadLevel(_levelId);
|
||||||
|
|
||||||
// 发送事件
|
// 发送事件
|
||||||
this.SendEvent(new LevelLoadedEvent(input.LevelId));
|
this.SendEvent(new LevelLoadedEvent(_levelId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -255,45 +323,32 @@ public class LoadLevelCommand : AbstractCommand<LoadLevelCommandInput>
|
|||||||
2. **命令无状态**:命令不应该保存长期状态,执行完即可丢弃
|
2. **命令无状态**:命令不应该保存长期状态,执行完即可丢弃
|
||||||
3. **参数通过构造函数传递**:命令需要的参数应在创建时传入
|
3. **参数通过构造函数传递**:命令需要的参数应在创建时传入
|
||||||
4. **避免命令嵌套**:命令内部尽量不要发送其他命令,使用事件通信
|
4. **避免命令嵌套**:命令内部尽量不要发送其他命令,使用事件通信
|
||||||
5. **合理使用返回值**:只在确实需要返回结果时使用 `AbstractCommand<TInput, TResult>`
|
5. **合理使用返回值**:只在确实需要返回结果时使用带返回值的命令
|
||||||
6. **命令命名规范**:使用动词+名词形式,如 `StartGameCommand`、`SavePlayerCommand`
|
6. **命令命名规范**:使用动词+名词形式,如 `StartGameCommand`、`SavePlayerCommand`
|
||||||
7. **输入参数结构化**:使用 `ICommandInput` 接口的实现类来组织命令参数
|
7. **单一职责原则**:每个命令只负责一个特定的业务操作
|
||||||
|
8. **使用异步命令**:对于需要长时间执行的操作,使用异步命令避免阻塞
|
||||||
|
9. **命令验证**:在命令执行前验证输入参数的有效性
|
||||||
|
10. **错误处理**:在命令中适当处理异常情况
|
||||||
|
|
||||||
## 扩展功能
|
## 命令模式优势
|
||||||
|
|
||||||
### 命令撤销/重做(可扩展)
|
### 1. 可扩展性
|
||||||
|
|
||||||
```csharp
|
- 命令可以被序列化和存储
|
||||||
public struct MoveCommandInput : ICommandInput
|
- 支持命令队列和批处理
|
||||||
{
|
- 便于实现撤销/重做功能
|
||||||
public Vector3 NewPosition { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// 实现可撤销命令
|
### 2. 可测试性
|
||||||
public class MoveCommand : AbstractCommand<MoveCommandInput>, IUndoableCommand
|
|
||||||
{
|
|
||||||
private Vector3 _oldPosition;
|
|
||||||
private Vector3 _newPosition;
|
|
||||||
|
|
||||||
public MoveCommand(MoveCommandInput input) : base(input)
|
|
||||||
{
|
|
||||||
_newPosition = input.NewPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnExecute(MoveCommandInput input)
|
- 命令逻辑独立,易于单元测试
|
||||||
{
|
- 可以模拟命令执行结果
|
||||||
var player = this.GetModel<PlayerModel>();
|
- 支持行为驱动开发
|
||||||
_oldPosition = player.Position;
|
|
||||||
player.Position = input.NewPosition;
|
### 3. 可维护性
|
||||||
}
|
|
||||||
|
- 业务逻辑集中管理
|
||||||
public void Undo()
|
- 降低组件间耦合度
|
||||||
{
|
- 便于重构和扩展
|
||||||
var player = this.GetModel<PlayerModel>();
|
|
||||||
player.Position = _oldPosition;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 相关包
|
## 相关包
|
||||||
|
|
||||||
@ -306,4 +361,4 @@ public class MoveCommand : AbstractCommand<MoveCommandInput>, IUndoableCommand
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**许可证**: Apache 2.0
|
**许可证**:Apache 2.0
|
||||||
@ -4,9 +4,11 @@
|
|||||||
|
|
||||||
Events 包提供了一套完整的事件系统,实现了观察者模式(Observer Pattern)。通过事件系统,可以实现组件间的松耦合通信,支持无参和带参事件、事件注册/注销、以及灵活的事件组合。
|
Events 包提供了一套完整的事件系统,实现了观察者模式(Observer Pattern)。通过事件系统,可以实现组件间的松耦合通信,支持无参和带参事件、事件注册/注销、以及灵活的事件组合。
|
||||||
|
|
||||||
|
事件系统是 GFramework 架构中组件间通信的核心机制,与命令模式和查询模式共同构成了完整的 CQRS 架构。
|
||||||
|
|
||||||
## 核心接口
|
## 核心接口
|
||||||
|
|
||||||
### 1. IEvent
|
### IEvent
|
||||||
|
|
||||||
基础事件接口,定义了事件注册的基本功能。
|
基础事件接口,定义了事件注册的基本功能。
|
||||||
|
|
||||||
@ -16,7 +18,7 @@ Events 包提供了一套完整的事件系统,实现了观察者模式(Obse
|
|||||||
IUnRegister Register(Action onEvent); // 注册事件处理函数
|
IUnRegister Register(Action onEvent); // 注册事件处理函数
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. IUnRegister
|
### IUnRegister
|
||||||
|
|
||||||
注销接口,用于取消事件注册。
|
注销接口,用于取消事件注册。
|
||||||
|
|
||||||
@ -26,7 +28,7 @@ IUnRegister Register(Action onEvent); // 注册事件处理函数
|
|||||||
void UnRegister(); // 执行注销操作
|
void UnRegister(); // 执行注销操作
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. IUnRegisterList
|
### IUnRegisterList
|
||||||
|
|
||||||
注销列表接口,用于批量管理注销对象。
|
注销列表接口,用于批量管理注销对象。
|
||||||
|
|
||||||
@ -36,7 +38,7 @@ void UnRegister(); // 执行注销操作
|
|||||||
IList<IUnRegister> UnregisterList { get; } // 获取注销列表
|
IList<IUnRegister> UnregisterList { get; } // 获取注销列表
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. IEventBus
|
### IEventBus
|
||||||
|
|
||||||
事件总线接口,提供基于类型的事件发送和注册。
|
事件总线接口,提供基于类型的事件发送和注册。
|
||||||
|
|
||||||
@ -46,14 +48,22 @@ IList<IUnRegister> UnregisterList { get; } // 获取注销列表
|
|||||||
IUnRegister Register<T>(Action<T> onEvent); // 注册类型化事件
|
IUnRegister Register<T>(Action<T> onEvent); // 注册类型化事件
|
||||||
void Send<T>(T e); // 发送事件实例
|
void Send<T>(T e); // 发送事件实例
|
||||||
void Send<T>() where T : new(); // 发送事件(自动创建实例)
|
void Send<T>() where T : new(); // 发送事件(自动创建实例)
|
||||||
|
void UnRegister<T>(Action<T> onEvent); // 注销事件监听器
|
||||||
```
|
```
|
||||||
|
|
||||||
## 核心类
|
## 核心类
|
||||||
|
|
||||||
### 1. EasyEvent
|
### EasyEvent
|
||||||
|
|
||||||
无参事件类,支持注册、注销和触发无参事件。
|
无参事件类,支持注册、注销和触发无参事件。
|
||||||
|
|
||||||
|
**核心方法:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
IUnRegister Register(Action onEvent); // 注册事件监听器
|
||||||
|
void Trigger(); // 触发事件
|
||||||
|
```
|
||||||
|
|
||||||
**使用示例:**
|
**使用示例:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
@ -63,7 +73,7 @@ var onClicked = new EasyEvent();
|
|||||||
// 注册监听
|
// 注册监听
|
||||||
var unregister = onClicked.Register(() =>
|
var unregister = onClicked.Register(() =>
|
||||||
{
|
{
|
||||||
GD.Print("Button clicked!");
|
Console.WriteLine("Button clicked!");
|
||||||
});
|
});
|
||||||
|
|
||||||
// 触发事件
|
// 触发事件
|
||||||
@ -73,10 +83,17 @@ onClicked.Trigger();
|
|||||||
unregister.UnRegister();
|
unregister.UnRegister();
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Event`<T>`
|
### Event`<T>`
|
||||||
|
|
||||||
单参数泛型事件类,支持一个参数的事件。
|
单参数泛型事件类,支持一个参数的事件。
|
||||||
|
|
||||||
|
**核心方法:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
IUnRegister Register(Action<T> onEvent); // 注册事件监听器
|
||||||
|
void Trigger(T eventData); // 触发事件并传递参数
|
||||||
|
```
|
||||||
|
|
||||||
**使用示例:**
|
**使用示例:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
@ -86,17 +103,24 @@ var onScoreChanged = new Event<int>();
|
|||||||
// 注册监听
|
// 注册监听
|
||||||
onScoreChanged.Register(newScore =>
|
onScoreChanged.Register(newScore =>
|
||||||
{
|
{
|
||||||
GD.Print($"Score changed to: {newScore}");
|
Console.WriteLine($"Score changed to: {newScore}");
|
||||||
});
|
});
|
||||||
|
|
||||||
// 触发事件并传递参数
|
// 触发事件并传递参数
|
||||||
onScoreChanged.Trigger(100);
|
onScoreChanged.Trigger(100);
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Event<T, TK>
|
### Event<T, TK>
|
||||||
|
|
||||||
双参数泛型事件类。
|
双参数泛型事件类。
|
||||||
|
|
||||||
|
**核心方法:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
IUnRegister Register(Action<T, TK> onEvent); // 注册事件监听器
|
||||||
|
void Trigger(T param1, TK param2); // 触发事件并传递两个参数
|
||||||
|
```
|
||||||
|
|
||||||
**使用示例:**
|
**使用示例:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
@ -105,16 +129,24 @@ var onDamageDealt = new Event<string, int>();
|
|||||||
|
|
||||||
onDamageDealt.Register((attacker, damage) =>
|
onDamageDealt.Register((attacker, damage) =>
|
||||||
{
|
{
|
||||||
GD.Print($"{attacker} dealt {damage} damage!");
|
Console.WriteLine($"{attacker} dealt {damage} damage!");
|
||||||
});
|
});
|
||||||
|
|
||||||
onDamageDealt.Trigger("Player", 50);
|
onDamageDealt.Trigger("Player", 50);
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. `EasyEvents`
|
### EasyEvents
|
||||||
|
|
||||||
全局事件管理器,提供类型安全的事件注册和获取。
|
全局事件管理器,提供类型安全的事件注册和获取。
|
||||||
|
|
||||||
|
**核心方法:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
static void Register<T>() where T : IEvent, new(); // 注册事件类型
|
||||||
|
static T Get<T>() where T : IEvent, new(); // 获取事件实例
|
||||||
|
static T GetOrAddEvent<T>() where T : IEvent, new(); // 获取或创建事件实例
|
||||||
|
```
|
||||||
|
|
||||||
**使用示例:**
|
**使用示例:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
@ -127,16 +159,25 @@ var gameStartEvent = EasyEvents.Get<GameStartEvent>();
|
|||||||
// 注册监听
|
// 注册监听
|
||||||
gameStartEvent.Register(() =>
|
gameStartEvent.Register(() =>
|
||||||
{
|
{
|
||||||
GD.Print("Game started!");
|
Console.WriteLine("Game started!");
|
||||||
});
|
});
|
||||||
|
|
||||||
// 触发事件
|
// 触发事件
|
||||||
gameStartEvent.Trigger();
|
gameStartEvent.Trigger();
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5. `EventBus`
|
### EventBus
|
||||||
|
|
||||||
类型化事件系统,支持基于类型的事件发送和注册。
|
类型化事件系统,支持基于类型的事件发送和注册。这是架构中默认的事件总线实现。
|
||||||
|
|
||||||
|
**核心方法:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
IUnRegister Register<T>(Action<T> onEvent); // 注册类型化事件
|
||||||
|
void Send<T>(T e); // 发送事件实例
|
||||||
|
void Send<T>() where T : new(); // 发送事件(自动创建实例)
|
||||||
|
void UnRegister<T>(Action<T> onEvent); // 注销事件监听器
|
||||||
|
```
|
||||||
|
|
||||||
**使用示例:**
|
**使用示例:**
|
||||||
|
|
||||||
@ -147,7 +188,7 @@ var eventBus = new EventBus();
|
|||||||
// 注册类型化事件
|
// 注册类型化事件
|
||||||
eventBus.Register<PlayerDiedEvent>(e =>
|
eventBus.Register<PlayerDiedEvent>(e =>
|
||||||
{
|
{
|
||||||
GD.Print($"Player died at position: {e.Position}");
|
Console.WriteLine($"Player died at position: {e.Position}");
|
||||||
});
|
});
|
||||||
|
|
||||||
// 发送事件(传递实例)
|
// 发送事件(传递实例)
|
||||||
@ -158,26 +199,35 @@ eventBus.Send(new PlayerDiedEvent
|
|||||||
|
|
||||||
// 发送事件(自动创建实例)
|
// 发送事件(自动创建实例)
|
||||||
eventBus.Send<PlayerDiedEvent>();
|
eventBus.Send<PlayerDiedEvent>();
|
||||||
|
|
||||||
|
// 注销事件监听器
|
||||||
|
eventBus.UnRegister<PlayerDiedEvent>(OnPlayerDied);
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6. `DefaultUnRegister`
|
### DefaultUnRegister
|
||||||
|
|
||||||
默认注销器实现,封装注销回调。
|
默认注销器实现,封装注销回调。
|
||||||
|
|
||||||
**使用示例:**
|
**使用示例:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
Action onUnregister = () => GD.Print("Unregistered");
|
Action onUnregister = () => Console.WriteLine("Unregistered");
|
||||||
var unregister = new DefaultUnRegister(onUnregister);
|
var unregister = new DefaultUnRegister(onUnregister);
|
||||||
|
|
||||||
// 执行注销
|
// 执行注销
|
||||||
unregister.UnRegister();
|
unregister.UnRegister();
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7. `OrEvent`
|
### OrEvent
|
||||||
|
|
||||||
事件或运算组合器,当任意一个事件触发时触发。
|
事件或运算组合器,当任意一个事件触发时触发。
|
||||||
|
|
||||||
|
**核心方法:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
OrEvent Or(IEvent @event); // 添加要组合的事件
|
||||||
|
```
|
||||||
|
|
||||||
**使用示例:**
|
**使用示例:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
@ -189,14 +239,21 @@ var onAnyInput = new OrEvent()
|
|||||||
// 当上述任意事件触发时,执行回调
|
// 当上述任意事件触发时,执行回调
|
||||||
onAnyInput.Register(() =>
|
onAnyInput.Register(() =>
|
||||||
{
|
{
|
||||||
GD.Print("Input detected!");
|
Console.WriteLine("Input detected!");
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### 8. `UnRegisterList`
|
### UnRegisterList
|
||||||
|
|
||||||
批量管理注销对象的列表。
|
批量管理注销对象的列表。
|
||||||
|
|
||||||
|
**核心方法:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
void Add(IUnRegister unRegister); // 添加注销器到列表
|
||||||
|
void UnRegisterAll(); // 批量注销所有事件
|
||||||
|
```
|
||||||
|
|
||||||
**使用示例:**
|
**使用示例:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
@ -209,7 +266,7 @@ someEvent.Register(OnEvent).AddToUnregisterList(unregisterList);
|
|||||||
unregisterList.UnRegisterAll();
|
unregisterList.UnRegisterAll();
|
||||||
```
|
```
|
||||||
|
|
||||||
### 9. `ArchitectureEvents`
|
### ArchitectureEvents
|
||||||
|
|
||||||
定义了架构生命周期相关的事件。
|
定义了架构生命周期相关的事件。
|
||||||
|
|
||||||
@ -317,18 +374,18 @@ public partial class GameController : Node, IController
|
|||||||
|
|
||||||
private void OnGameStarted(GameStartedEvent e)
|
private void OnGameStarted(GameStartedEvent e)
|
||||||
{
|
{
|
||||||
GD.Print("Game started!");
|
Console.WriteLine("Game started!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPlayerDied(PlayerDiedEvent e)
|
private void OnPlayerDied(PlayerDiedEvent e)
|
||||||
{
|
{
|
||||||
GD.Print($"Player died at {e.Position}: {e.Cause}");
|
Console.WriteLine($"Player died at {e.Position}: {e.Cause}");
|
||||||
ShowGameOverScreen();
|
ShowGameOverScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnLevelCompleted(LevelCompletedEvent e)
|
private void OnLevelCompleted(LevelCompletedEvent e)
|
||||||
{
|
{
|
||||||
GD.Print($"Level {e.LevelId} completed! Score: {e.Score}");
|
Console.WriteLine($"Level {e.LevelId} completed! Score: {e.Score}");
|
||||||
ShowVictoryScreen(e);
|
ShowVictoryScreen(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,6 +560,11 @@ public override void _Ready()
|
|||||||
- 事件处理器保持轻量
|
- 事件处理器保持轻量
|
||||||
- 使用结构体事件减少 GC
|
- 使用结构体事件减少 GC
|
||||||
|
|
||||||
|
7. **事件设计原则**
|
||||||
|
- 高内聚:事件应该代表一个完整的业务概念
|
||||||
|
- 低耦合:事件发送者不需要知道接收者
|
||||||
|
- 可测试:事件应该易于模拟和测试
|
||||||
|
|
||||||
## 事件 vs 其他通信方式
|
## 事件 vs 其他通信方式
|
||||||
|
|
||||||
| 方式 | 适用场景 | 优点 | 缺点 |
|
| 方式 | 适用场景 | 优点 | 缺点 |
|
||||||
@ -512,6 +574,23 @@ public override void _Ready()
|
|||||||
| **Query** | 查询数据 | 职责清晰、有返回值 | 同步调用 |
|
| **Query** | 查询数据 | 职责清晰、有返回值 | 同步调用 |
|
||||||
| **BindableProperty** | UI 数据绑定 | 自动更新、响应式 | 仅限单一属性 |
|
| **BindableProperty** | UI 数据绑定 | 自动更新、响应式 | 仅限单一属性 |
|
||||||
|
|
||||||
|
## 事件系统架构
|
||||||
|
|
||||||
|
事件系统在 GFramework 中的架构位置:
|
||||||
|
|
||||||
|
```
|
||||||
|
Architecture (架构核心)
|
||||||
|
├── EventBus (事件总线)
|
||||||
|
├── CommandBus (命令总线)
|
||||||
|
├── QueryBus (查询总线)
|
||||||
|
└── IocContainer (IoC容器)
|
||||||
|
|
||||||
|
Components (组件)
|
||||||
|
├── Model (发送事件)
|
||||||
|
├── System (发送/接收事件)
|
||||||
|
└── Controller (接收事件)
|
||||||
|
```
|
||||||
|
|
||||||
## 相关包
|
## 相关包
|
||||||
|
|
||||||
- [`architecture`](./architecture.md) - 提供全局事件系统
|
- [`architecture`](./architecture.md) - 提供全局事件系统
|
||||||
@ -519,4 +598,6 @@ public override void _Ready()
|
|||||||
- [`property`](./property.md) - 可绑定属性基于事件实现
|
- [`property`](./property.md) - 可绑定属性基于事件实现
|
||||||
- [`controller`](./controller.md) - 控制器监听事件
|
- [`controller`](./controller.md) - 控制器监听事件
|
||||||
- [`model`](./model.md) - 模型发送事件
|
- [`model`](./model.md) - 模型发送事件
|
||||||
- [`system`](./system.md) - 系统发送和监听事件
|
- [`system`](./system.md) - 系统发送和监听事件
|
||||||
|
- [`command`](./command.md) - 与事件配合实现 CQRS
|
||||||
|
- [`query`](./query.md) - 与事件配合实现 CQRS
|
||||||
@ -5,12 +5,20 @@
|
|||||||
IoC(Inversion of Control,控制反转)包提供了一个轻量级的依赖注入容器,用于管理框架中各种组件的注册和获取。通过 IoC
|
IoC(Inversion of Control,控制反转)包提供了一个轻量级的依赖注入容器,用于管理框架中各种组件的注册和获取。通过 IoC
|
||||||
容器,可以实现组件间的解耦,便于测试和维护。
|
容器,可以实现组件间的解耦,便于测试和维护。
|
||||||
|
|
||||||
|
IoC 容器是 GFramework 架构的核心组件之一,为整个框架提供依赖管理和组件解析服务。
|
||||||
|
|
||||||
## 核心类
|
## 核心类
|
||||||
|
|
||||||
### `IocContainer`
|
### IocContainer
|
||||||
|
|
||||||
IoC 容器类,负责管理对象的注册和获取。
|
IoC 容器类,负责管理对象的注册和获取。
|
||||||
|
|
||||||
|
**继承关系:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class IocContainer : ContextAwareBase, IIocContainer
|
||||||
|
```
|
||||||
|
|
||||||
**主要功能:**
|
**主要功能:**
|
||||||
|
|
||||||
- 注册实例到容器
|
- 注册实例到容器
|
||||||
@ -18,13 +26,16 @@ IoC 容器类,负责管理对象的注册和获取。
|
|||||||
- 类型安全的依赖管理
|
- 类型安全的依赖管理
|
||||||
- 线程安全操作
|
- 线程安全操作
|
||||||
- 容器冻结保护
|
- 容器冻结保护
|
||||||
|
- 多实例注册支持
|
||||||
|
|
||||||
## 核心方法
|
## 核心方法
|
||||||
|
|
||||||
### 1. Register`<T>` 和 Register(Type, object)
|
### Register`<T>` 和 Register(Type, object)
|
||||||
|
|
||||||
注册一个实例到容器中。
|
注册一个实例到容器中。
|
||||||
|
|
||||||
|
**方法签名:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public void Register<T>(T instance)
|
public void Register<T>(T instance)
|
||||||
public void Register(Type type, object instance)
|
public void Register(Type type, object instance)
|
||||||
@ -35,6 +46,13 @@ public void Register(Type type, object instance)
|
|||||||
- `instance`: 要注册的实例对象
|
- `instance`: 要注册的实例对象
|
||||||
- `type`: 要注册的类型(重载方法)
|
- `type`: 要注册的类型(重载方法)
|
||||||
|
|
||||||
|
**特点:**
|
||||||
|
|
||||||
|
- 支持泛型和非泛型注册
|
||||||
|
- 自动注册到实例的所有接口类型
|
||||||
|
- 线程安全操作
|
||||||
|
- 容器冻结后抛出异常
|
||||||
|
|
||||||
**使用示例:**
|
**使用示例:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
@ -44,12 +62,17 @@ var container = new IocContainer();
|
|||||||
container.Register<IPlayerModel>(new PlayerModel());
|
container.Register<IPlayerModel>(new PlayerModel());
|
||||||
container.Register<IGameSystem>(new GameSystem());
|
container.Register<IGameSystem>(new GameSystem());
|
||||||
container.Register<IStorageUtility>(new StorageUtility());
|
container.Register<IStorageUtility>(new StorageUtility());
|
||||||
|
|
||||||
|
// 非泛型注册
|
||||||
|
container.Register(typeof(ICustomService), new CustomService());
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. RegisterSingleton`<T>`
|
### RegisterSingleton`<T>`
|
||||||
|
|
||||||
注册单例实例到容器中。一个类型只允许一个实例。
|
注册单例实例到容器中。一个类型只允许一个实例。
|
||||||
|
|
||||||
|
**方法签名:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public void RegisterSingleton<T>(T instance)
|
public void RegisterSingleton<T>(T instance)
|
||||||
```
|
```
|
||||||
@ -58,6 +81,12 @@ public void RegisterSingleton<T>(T instance)
|
|||||||
|
|
||||||
- `instance`: 要注册的单例实例
|
- `instance`: 要注册的单例实例
|
||||||
|
|
||||||
|
**特点:**
|
||||||
|
|
||||||
|
- 严格单例约束:同一类型只能注册一个实例
|
||||||
|
- 重复注册会抛出 `InvalidOperationException`
|
||||||
|
- 适用于全局服务和配置对象
|
||||||
|
|
||||||
**使用示例:**
|
**使用示例:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
@ -65,12 +94,18 @@ var container = new IocContainer();
|
|||||||
|
|
||||||
// 注册单例
|
// 注册单例
|
||||||
container.RegisterSingleton<IPlayerModel>(new PlayerModel());
|
container.RegisterSingleton<IPlayerModel>(new PlayerModel());
|
||||||
|
container.RegisterSingleton<IGameConfiguration>(new GameConfiguration());
|
||||||
|
|
||||||
|
// 以下会抛出异常(重复注册)
|
||||||
|
// container.RegisterSingleton<IPlayerModel>(new AnotherPlayerModel());
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. RegisterPlurality
|
### RegisterPlurality
|
||||||
|
|
||||||
注册多个实例,将实例注册到其实现的所有接口和具体类型上。
|
注册多个实例,将实例注册到其实现的所有接口和具体类型上。
|
||||||
|
|
||||||
|
**方法签名:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public void RegisterPlurality(object instance)
|
public void RegisterPlurality(object instance)
|
||||||
```
|
```
|
||||||
@ -79,10 +114,34 @@ public void RegisterPlurality(object instance)
|
|||||||
|
|
||||||
- `instance`: 要注册的实例
|
- `instance`: 要注册的实例
|
||||||
|
|
||||||
### 4. RegisterSystem
|
**特点:**
|
||||||
|
|
||||||
|
- 自动注册到所有实现的接口
|
||||||
|
- 同时注册具体类型
|
||||||
|
- 支持多态注册
|
||||||
|
- 常用于 System 和 Utility 注册
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var container = new IocContainer();
|
||||||
|
|
||||||
|
// 假设 GameSystem 实现了 IGameSystem 和 IUpdateable 接口
|
||||||
|
var gameSystem = new GameSystem();
|
||||||
|
container.RegisterPlurality(gameSystem);
|
||||||
|
|
||||||
|
// 现在可以通过任一接口获取
|
||||||
|
var system1 = container.Get<IGameSystem>(); // 返回 gameSystem
|
||||||
|
var system2 = container.Get<IUpdateable>(); // 返回 gameSystem
|
||||||
|
var system3 = container.Get<GameSystem>(); // 返回 gameSystem
|
||||||
|
```
|
||||||
|
|
||||||
|
### RegisterSystem
|
||||||
|
|
||||||
注册系统实例,将其绑定到其所有实现的接口上。
|
注册系统实例,将其绑定到其所有实现的接口上。
|
||||||
|
|
||||||
|
**方法签名:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public void RegisterSystem(ISystem system)
|
public void RegisterSystem(ISystem system)
|
||||||
```
|
```
|
||||||
@ -91,10 +150,29 @@ public void RegisterSystem(ISystem system)
|
|||||||
|
|
||||||
- `system`: 系统实例对象
|
- `system`: 系统实例对象
|
||||||
|
|
||||||
### 5. Get`<T>` 和 GetAll`<T>`
|
**特点:**
|
||||||
|
|
||||||
|
- 专门为 System 设计的注册方法
|
||||||
|
- 内部调用 `RegisterPlurality`
|
||||||
|
- 提供语义化的 API
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var container = new IocContainer();
|
||||||
|
|
||||||
|
// 注册系统
|
||||||
|
container.RegisterSystem(new CombatSystem());
|
||||||
|
container.RegisterSystem(new InventorySystem());
|
||||||
|
container.RegisterSystem(new QuestSystem());
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get`<T>` 和 GetAll`<T>`
|
||||||
|
|
||||||
从容器中获取指定类型的实例。
|
从容器中获取指定类型的实例。
|
||||||
|
|
||||||
|
**方法签名:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public T? Get<T>() where T : class
|
public T? Get<T>() where T : class
|
||||||
public IReadOnlyList<T> GetAll<T>() where T : class
|
public IReadOnlyList<T> GetAll<T>() where T : class
|
||||||
@ -105,6 +183,12 @@ public IReadOnlyList<T> GetAll<T>() where T : class
|
|||||||
- `Get<T>`: 返回指定类型的实例,如果未找到则返回 `null`
|
- `Get<T>`: 返回指定类型的实例,如果未找到则返回 `null`
|
||||||
- `GetAll<T>`: 返回指定类型的所有实例列表,如果未找到则返回空数组
|
- `GetAll<T>`: 返回指定类型的所有实例列表,如果未找到则返回空数组
|
||||||
|
|
||||||
|
**特点:**
|
||||||
|
|
||||||
|
- 线程安全读取
|
||||||
|
- 支持接口和具体类型查询
|
||||||
|
- 返回值快照(线程安全)
|
||||||
|
|
||||||
**使用示例:**
|
**使用示例:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
@ -114,12 +198,15 @@ var gameSystems = container.GetAll<IGameSystem>();
|
|||||||
|
|
||||||
// 如果类型未注册,Get 返回 null,GetAll 返回空数组
|
// 如果类型未注册,Get 返回 null,GetAll 返回空数组
|
||||||
var unknownService = container.Get<IUnknownService>(); // null
|
var unknownService = container.Get<IUnknownService>(); // null
|
||||||
|
var allUnknownServices = container.GetAll<IUnknownService>(); // 空数组
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6. GetRequired`<T>`
|
### GetRequired`<T>`
|
||||||
|
|
||||||
获取指定类型的必需实例,如果没有注册或注册了多个实例会抛出异常。
|
获取指定类型的必需实例,如果没有注册或注册了多个实例会抛出异常。
|
||||||
|
|
||||||
|
**方法签名:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public T GetRequired<T>() where T : class
|
public T GetRequired<T>() where T : class
|
||||||
```
|
```
|
||||||
@ -128,10 +215,30 @@ public T GetRequired<T>() where T : class
|
|||||||
|
|
||||||
- 返回找到的唯一实例
|
- 返回找到的唯一实例
|
||||||
|
|
||||||
### 7. GetAllSorted`<T>`
|
**特点:**
|
||||||
|
|
||||||
|
- 严格模式获取
|
||||||
|
- 无实例时抛出 `InvalidOperationException`
|
||||||
|
- 多实例时抛出 `InvalidOperationException`
|
||||||
|
- 适用于必需的单例依赖
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 获取必需的服务
|
||||||
|
var config = container.GetRequired<IGameConfiguration>(); // 必须存在且唯一
|
||||||
|
|
||||||
|
// 以下情况会抛出异常:
|
||||||
|
// 1. IGameConfiguration 未注册
|
||||||
|
// 2. IGameConfiguration 注册了多个实例
|
||||||
|
```
|
||||||
|
|
||||||
|
### GetAllSorted`<T>`
|
||||||
|
|
||||||
获取并排序(系统调度专用)。
|
获取并排序(系统调度专用)。
|
||||||
|
|
||||||
|
**方法签名:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public IReadOnlyList<T> GetAllSorted<T>(Comparison<T> comparison) where T : class
|
public IReadOnlyList<T> GetAllSorted<T>(Comparison<T> comparison) where T : class
|
||||||
```
|
```
|
||||||
@ -144,24 +251,71 @@ public IReadOnlyList<T> GetAllSorted<T>(Comparison<T> comparison) where T : clas
|
|||||||
|
|
||||||
- 按指定方式排序后的实例列表
|
- 按指定方式排序后的实例列表
|
||||||
|
|
||||||
|
**特点:**
|
||||||
|
|
||||||
|
- 支持自定义排序
|
||||||
|
- 适用于需要按优先级执行的场景
|
||||||
|
- 常用于 System 更新顺序控制
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 按优先级排序系统
|
||||||
|
var sortedSystems = container.GetAllSorted<ISystem>((a, b) =>
|
||||||
|
{
|
||||||
|
var priorityA = GetSystemPriority(a);
|
||||||
|
var priorityB = GetSystemPriority(b);
|
||||||
|
return priorityA.CompareTo(priorityB);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## IoC 容器架构
|
||||||
|
|
||||||
|
```
|
||||||
|
Architecture (架构层)
|
||||||
|
├── IocContainer (IoC容器)
|
||||||
|
│ ├── Register<T>() // 泛型注册
|
||||||
|
│ ├── Register(Type, obj) // 非泛型注册
|
||||||
|
│ ├── RegisterSingleton<T>() // 单例注册
|
||||||
|
│ ├── RegisterPlurality() // 多态注册
|
||||||
|
│ ├── RegisterSystem() // 系统注册
|
||||||
|
│ ├── Get<T>() // 获取实例
|
||||||
|
│ ├── GetAll<T>() // 获取所有实例
|
||||||
|
│ ├── GetRequired<T>() // 获取必需实例
|
||||||
|
│ ├── GetAllSorted<T>() // 排序获取
|
||||||
|
│ ├── Contains<T>() // 检查存在性
|
||||||
|
│ ├── ContainsInstance() // 检查实例
|
||||||
|
│ ├── Clear() // 清空容器
|
||||||
|
│ └── Freeze() // 冻结容器
|
||||||
|
│
|
||||||
|
├── Components (组件)
|
||||||
|
│ ├── Model (数据模型)
|
||||||
|
│ ├── System (业务系统)
|
||||||
|
│ └── Utility (工具类)
|
||||||
|
│
|
||||||
|
└── Context (上下文)
|
||||||
|
└── 提供容器访问
|
||||||
|
```
|
||||||
|
|
||||||
## 在框架中的使用
|
## 在框架中的使用
|
||||||
|
|
||||||
### Architecture 中的应用
|
### Architecture 中的应用
|
||||||
|
|
||||||
IoC 容器是 [`Architecture`](./architecture.md) 类的核心组件,用于管理所有的 System、Model 和 Utility。
|
IoC 容器是 [`Architecture`](./architecture.md) 类的核心组件,用于管理所有的 System、Model 和 Utility。
|
||||||
|
|
||||||
```
|
```csharp
|
||||||
public abstract class Architecture : IArchitecture
|
public abstract class Architecture : IArchitecture
|
||||||
{
|
{
|
||||||
// 内置 IoC 容器
|
// 内置 IoC 容器
|
||||||
private readonly IocContainer _mContainer = new();
|
private readonly IocContainer _mContainer = new();
|
||||||
|
|
||||||
// 注册系统
|
// 注册系统
|
||||||
public void RegisterSystem<TSystem>(TSystem system) where TSystem : ISystem
|
public TSystem RegisterSystem<TSystem>(TSystem system) where TSystem : ISystem
|
||||||
{
|
{
|
||||||
system.SetArchitecture(this);
|
system.SetContext(Context);
|
||||||
_mContainer.Register(system); // 注册到容器
|
_mContainer.RegisterPlurality(system); // 注册到容器
|
||||||
// ...
|
RegisterLifecycleComponent(system); // 处理生命周期
|
||||||
|
return system;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取系统
|
// 获取系统
|
||||||
@ -169,6 +323,16 @@ public abstract class Architecture : IArchitecture
|
|||||||
=> _mContainer.Get<TSystem>(); // 从容器获取
|
=> _mContainer.Get<TSystem>(); // 从容器获取
|
||||||
|
|
||||||
// Model 和 Utility 同理
|
// Model 和 Utility 同理
|
||||||
|
public TModel RegisterModel<TModel>(TModel model) where TModel : IModel
|
||||||
|
{
|
||||||
|
model.SetContext(Context);
|
||||||
|
_mContainer.RegisterPlurality(model);
|
||||||
|
RegisterLifecycleComponent(model);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TModel GetModel<TModel>() where TModel : class, IModel
|
||||||
|
=> _mContainer.Get<TModel>();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -4,9 +4,11 @@
|
|||||||
|
|
||||||
Property 包提供了可绑定属性(BindableProperty)的实现,支持属性值的监听和响应式编程。这是实现数据绑定和响应式编程的核心组件。
|
Property 包提供了可绑定属性(BindableProperty)的实现,支持属性值的监听和响应式编程。这是实现数据绑定和响应式编程的核心组件。
|
||||||
|
|
||||||
|
BindableProperty 是 GFramework 中 Model 层数据管理的基础,通过事件机制实现属性变化的通知。
|
||||||
|
|
||||||
## 核心接口
|
## 核心接口
|
||||||
|
|
||||||
### [`IReadonlyBindableProperty<T>`](./property.md)
|
### IReadonlyBindableProperty`<T>`
|
||||||
|
|
||||||
只读可绑定属性接口,提供属性值的读取和变更监听功能。
|
只读可绑定属性接口,提供属性值的读取和变更监听功能。
|
||||||
|
|
||||||
@ -26,7 +28,7 @@ IUnRegister RegisterWithInitValue(Action<T> action);
|
|||||||
void UnRegister(Action<T> onValueChanged);
|
void UnRegister(Action<T> onValueChanged);
|
||||||
```
|
```
|
||||||
|
|
||||||
### [`IBindableProperty<T>`](./property.md)
|
### IBindableProperty`<T>`
|
||||||
|
|
||||||
可绑定属性接口,继承自只读接口,增加了修改能力。
|
可绑定属性接口,继承自只读接口,增加了修改能力。
|
||||||
|
|
||||||
@ -42,10 +44,33 @@ void SetValueWithoutEvent(T newValue);
|
|||||||
|
|
||||||
## 核心类
|
## 核心类
|
||||||
|
|
||||||
### [`BindableProperty<T>`](./property.md)
|
### BindableProperty`<T>`
|
||||||
|
|
||||||
可绑定属性的完整实现。
|
可绑定属性的完整实现。
|
||||||
|
|
||||||
|
**核心方法:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 构造函数
|
||||||
|
BindableProperty(T defaultValue = default!);
|
||||||
|
|
||||||
|
// 属性值
|
||||||
|
T Value { get; set; }
|
||||||
|
|
||||||
|
// 注册监听
|
||||||
|
IUnRegister Register(Action<T> onValueChanged);
|
||||||
|
IUnRegister RegisterWithInitValue(Action<T> action);
|
||||||
|
|
||||||
|
// 取消监听
|
||||||
|
void UnRegister(Action<T> onValueChanged);
|
||||||
|
|
||||||
|
// 设置值但不触发事件
|
||||||
|
void SetValueWithoutEvent(T newValue);
|
||||||
|
|
||||||
|
// 设置自定义比较器
|
||||||
|
BindableProperty<T> WithComparer(Func<T, T, bool> comparer);
|
||||||
|
```
|
||||||
|
|
||||||
**使用示例:**
|
**使用示例:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
@ -55,7 +80,7 @@ var health = new BindableProperty<int>(100);
|
|||||||
// 监听值变化(不会立即触发)
|
// 监听值变化(不会立即触发)
|
||||||
var unregister = health.Register(newValue =>
|
var unregister = health.Register(newValue =>
|
||||||
{
|
{
|
||||||
GD.Print($"Health changed to: {newValue}");
|
Console.WriteLine($"Health changed to: {newValue}");
|
||||||
});
|
});
|
||||||
|
|
||||||
// 设置值(会触发监听器)
|
// 设置值(会触发监听器)
|
||||||
@ -74,7 +99,7 @@ health.SetValueWithoutEvent(75);
|
|||||||
// 1. 注册并立即获得当前值
|
// 1. 注册并立即获得当前值
|
||||||
health.RegisterWithInitValue(value =>
|
health.RegisterWithInitValue(value =>
|
||||||
{
|
{
|
||||||
GD.Print($"Current health: {value}"); // 立即输出当前值
|
Console.WriteLine($"Current health: {value}"); // 立即输出当前值
|
||||||
// 后续值变化时也会调用
|
// 后续值变化时也会调用
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -84,9 +109,13 @@ BindableProperty<int>.Comparer = (a, b) => Math.Abs(a - b) < 1;
|
|||||||
// 3. 使用实例方法设置比较器
|
// 3. 使用实例方法设置比较器
|
||||||
var position = new BindableProperty<Vector3>(Vector3.Zero)
|
var position = new BindableProperty<Vector3>(Vector3.Zero)
|
||||||
.WithComparer((a, b) => a.DistanceTo(b) < 0.01f); // 距离小于0.01认为相等
|
.WithComparer((a, b) => a.DistanceTo(b) < 0.01f); // 距离小于0.01认为相等
|
||||||
|
|
||||||
|
// 4. 字符串比较器示例
|
||||||
|
var name = new BindableProperty<string>("Player")
|
||||||
|
.WithComparer((a, b) => string.Equals(a, b, StringComparison.OrdinalIgnoreCase));
|
||||||
```
|
```
|
||||||
|
|
||||||
### [`BindablePropertyUnRegister<T>`](./property.md)
|
### BindablePropertyUnRegister`<T>`
|
||||||
|
|
||||||
可绑定属性的注销器,负责清理监听。
|
可绑定属性的注销器,负责清理监听。
|
||||||
|
|
||||||
@ -98,6 +127,15 @@ var unregister = health.Register(OnHealthChanged);
|
|||||||
unregister.UnRegister();
|
unregister.UnRegister();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## BindableProperty 工作原理
|
||||||
|
|
||||||
|
BindableProperty 基于事件系统实现属性变化通知:
|
||||||
|
|
||||||
|
1. **值设置**:当设置 `Value` 属性时,首先进行值比较
|
||||||
|
2. **变化检测**:使用 `EqualityComparer<T>.Default` 或自定义比较器检测值变化
|
||||||
|
3. **事件触发**:如果值发生变化,调用所有注册的回调函数
|
||||||
|
4. **内存管理**:通过 `IUnRegister` 机制管理监听器的生命周期
|
||||||
|
|
||||||
## 在 Model 中使用
|
## 在 Model 中使用
|
||||||
|
|
||||||
### 定义可绑定属性
|
### 定义可绑定属性
|
||||||
@ -110,6 +148,7 @@ public class PlayerModel : AbstractModel
|
|||||||
public BindableProperty<int> Level { get; } = new(1);
|
public BindableProperty<int> Level { get; } = new(1);
|
||||||
public BindableProperty<int> Health { get; } = new(100);
|
public BindableProperty<int> Health { get; } = new(100);
|
||||||
public BindableProperty<int> MaxHealth { get; } = new(100);
|
public BindableProperty<int> MaxHealth { get; } = new(100);
|
||||||
|
public BindableProperty<Vector3> Position { get; } = new(Vector3.Zero);
|
||||||
|
|
||||||
// 只读属性(外部只能读取和监听)
|
// 只读属性(外部只能读取和监听)
|
||||||
public IReadonlyBindableProperty<int> ReadonlyHealth => Health;
|
public IReadonlyBindableProperty<int> ReadonlyHealth => Health;
|
||||||
@ -123,7 +162,33 @@ public class PlayerModel : AbstractModel
|
|||||||
{
|
{
|
||||||
this.SendEvent(new PlayerDiedEvent());
|
this.SendEvent(new PlayerDiedEvent());
|
||||||
}
|
}
|
||||||
|
else if (hp < MaxHealth.Value * 0.3f)
|
||||||
|
{
|
||||||
|
this.SendEvent(new LowHealthWarningEvent());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 监听等级变化
|
||||||
|
Level.Register(newLevel =>
|
||||||
|
{
|
||||||
|
this.SendEvent(new PlayerLevelUpEvent { NewLevel = newLevel });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 业务方法
|
||||||
|
public void TakeDamage(int damage)
|
||||||
|
{
|
||||||
|
Health.Value = Math.Max(0, Health.Value - damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Heal(int amount)
|
||||||
|
{
|
||||||
|
Health.Value = Math.Min(MaxHealth.Value, Health.Value + amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetHealthPercentage()
|
||||||
|
{
|
||||||
|
return (float)Health.Value / MaxHealth.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -137,6 +202,7 @@ public partial class PlayerUI : Control, IController
|
|||||||
{
|
{
|
||||||
[Export] private Label _healthLabel;
|
[Export] private Label _healthLabel;
|
||||||
[Export] private Label _nameLabel;
|
[Export] private Label _nameLabel;
|
||||||
|
[Export] private ProgressBar _healthBar;
|
||||||
|
|
||||||
private IUnRegisterList _unregisterList = new UnRegisterList();
|
private IUnRegisterList _unregisterList = new UnRegisterList();
|
||||||
|
|
||||||
@ -151,6 +217,15 @@ public partial class PlayerUI : Control, IController
|
|||||||
.RegisterWithInitValue(health =>
|
.RegisterWithInitValue(health =>
|
||||||
{
|
{
|
||||||
_healthLabel.Text = $"HP: {health}/{playerModel.MaxHealth.Value}";
|
_healthLabel.Text = $"HP: {health}/{playerModel.MaxHealth.Value}";
|
||||||
|
_healthBar.Value = (float)health / playerModel.MaxHealth.Value * 100;
|
||||||
|
})
|
||||||
|
.AddToUnregisterList(_unregisterList);
|
||||||
|
|
||||||
|
// 绑定最大生命值
|
||||||
|
playerModel.MaxHealth
|
||||||
|
.RegisterWithInitValue(maxHealth =>
|
||||||
|
{
|
||||||
|
_healthBar.MaxValue = maxHealth;
|
||||||
})
|
})
|
||||||
.AddToUnregisterList(_unregisterList);
|
.AddToUnregisterList(_unregisterList);
|
||||||
|
|
||||||
@ -161,6 +236,17 @@ public partial class PlayerUI : Control, IController
|
|||||||
_nameLabel.Text = name;
|
_nameLabel.Text = name;
|
||||||
})
|
})
|
||||||
.AddToUnregisterList(_unregisterList);
|
.AddToUnregisterList(_unregisterList);
|
||||||
|
|
||||||
|
// 绑定位置(仅用于调试显示)
|
||||||
|
playerModel.Position
|
||||||
|
.RegisterWithInitValue(pos =>
|
||||||
|
{
|
||||||
|
// 仅在调试模式下显示
|
||||||
|
#if DEBUG
|
||||||
|
Console.WriteLine($"Player position: {pos}");
|
||||||
|
#endif
|
||||||
|
})
|
||||||
|
.AddToUnregisterList(_unregisterList);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _ExitTree()
|
public override void _ExitTree()
|
||||||
|
|||||||
@ -5,6 +5,8 @@
|
|||||||
Query 包实现了 CQRS(命令查询职责分离)模式中的查询部分。Query 用于封装数据查询逻辑,与 Command 不同的是,Query
|
Query 包实现了 CQRS(命令查询职责分离)模式中的查询部分。Query 用于封装数据查询逻辑,与 Command 不同的是,Query
|
||||||
有返回值且不应该修改系统状态。
|
有返回值且不应该修改系统状态。
|
||||||
|
|
||||||
|
查询系统是 GFramework CQRS 架构的重要组成部分,专门负责数据读取操作,与命令系统和事件系统协同工作。
|
||||||
|
|
||||||
## 核心接口
|
## 核心接口
|
||||||
|
|
||||||
### IQuery`<TResult>`
|
### IQuery`<TResult>`
|
||||||
@ -19,22 +21,28 @@ TResult Do(); // 执行查询并返回结果
|
|||||||
|
|
||||||
## 核心类
|
## 核心类
|
||||||
|
|
||||||
### [`AbstractQuery<TInput, TResult>`](./query.md)
|
### AbstractQuery`<TResult>`
|
||||||
|
|
||||||
抽象查询基类,提供了查询的基础实现。它接受一个泛型输入参数 TInput,该参数必须实现 IQueryInput 接口。
|
抽象查询基类,提供了查询的基础实现。
|
||||||
|
|
||||||
|
**核心方法:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
TResult IQuery<TResult>.Do(); // 实现 IQuery 接口
|
||||||
|
protected abstract TResult OnDo(); // 抽象查询方法,由子类实现
|
||||||
|
```
|
||||||
|
|
||||||
**使用方式:**
|
**使用方式:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public abstract class AbstractQuery<TInput, TResult>(TInput input) : ContextAwareBase, IQuery<TResult>
|
public abstract class AbstractQuery<TResult> : ContextAwareBase, IQuery<TResult>
|
||||||
where TInput : IQueryInput
|
|
||||||
{
|
{
|
||||||
public TResult Do() => OnDo(input); // 执行查询,传入输入参数
|
public TResult Do() => OnDo(); // 执行查询
|
||||||
protected abstract TResult OnDo(TInput input); // 子类实现查询逻辑
|
protected abstract TResult OnDo(); // 子类实现查询逻辑
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### [`EmptyQueryInput`](./query.md)
|
### EmptyQueryInput
|
||||||
|
|
||||||
空查询输入类,用于表示不需要任何输入参数的查询操作。
|
空查询输入类,用于表示不需要任何输入参数的查询操作。
|
||||||
|
|
||||||
@ -47,10 +55,16 @@ public sealed class EmptyQueryInput : IQueryInput
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### [`QueryBus`](./query.md)
|
### QueryBus
|
||||||
|
|
||||||
查询总线实现,负责执行查询并返回结果。
|
查询总线实现,负责执行查询并返回结果。
|
||||||
|
|
||||||
|
**核心方法:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
TResult Send<TResult>(IQuery<TResult> query); // 发送并执行查询
|
||||||
|
```
|
||||||
|
|
||||||
**使用方式:**
|
**使用方式:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
@ -69,56 +83,41 @@ public sealed class QueryBus : IQueryBus
|
|||||||
### 1. 定义查询
|
### 1. 定义查询
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// 定义查询输入参数
|
|
||||||
public record GetPlayerGoldQueryInput : IQueryInput;
|
|
||||||
|
|
||||||
// 查询玩家金币数量
|
// 查询玩家金币数量
|
||||||
public class GetPlayerGoldQuery : AbstractQuery<GetPlayerGoldQueryInput, int>
|
public class GetPlayerGoldQuery : AbstractQuery<int>
|
||||||
{
|
{
|
||||||
public GetPlayerGoldQuery() : base(new EmptyQueryInput())
|
protected override int OnDo()
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override int OnDo(GetPlayerGoldQueryInput input)
|
|
||||||
{
|
{
|
||||||
return this.GetModel<PlayerModel>().Gold.Value;
|
return this.GetModel<PlayerModel>().Gold.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询玩家是否死亡
|
// 查询玩家是否死亡
|
||||||
public record IsPlayerDeadQueryInput : IQueryInput;
|
public class IsPlayerDeadQuery : AbstractQuery<bool>
|
||||||
|
|
||||||
public class IsPlayerDeadQuery : AbstractQuery<IsPlayerDeadQueryInput, bool>
|
|
||||||
{
|
{
|
||||||
public IsPlayerDeadQuery() : base(new EmptyQueryInput())
|
protected override bool OnDo()
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnDo(IsPlayerDeadQueryInput input)
|
|
||||||
{
|
{
|
||||||
return this.GetModel<PlayerModel>().Health.Value <= 0;
|
return this.GetModel<PlayerModel>().Health.Value <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询背包中指定物品的数量
|
// 查询背包中指定物品的数量
|
||||||
public record GetItemCountQueryInput(string ItemId) : IQueryInput;
|
public class GetItemCountQuery : AbstractQuery<int>
|
||||||
|
|
||||||
public class GetItemCountQuery : AbstractQuery<GetItemCountQueryInput, int>
|
|
||||||
{
|
{
|
||||||
public GetItemCountQuery(string itemId) : base(new GetItemCountQueryInput(itemId))
|
private readonly string _itemId;
|
||||||
{
|
|
||||||
}
|
public GetItemCountQuery(string itemId)
|
||||||
|
|
||||||
protected override int OnDo(GetItemCountQueryInput input)
|
|
||||||
{
|
{
|
||||||
var inventory = this.GetModel<InventoryModel>();
|
_itemId = itemId;
|
||||||
return inventory.GetItemCount(input.ItemId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override int OnDo()
|
||||||
|
{
|
||||||
|
var inventory = this.GetModel<InventoryModel>();
|
||||||
|
return inventory.GetItemCount(_itemId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
```
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. 发送查询
|
### 2. 发送查询
|
||||||
@ -144,11 +143,11 @@ public partial class ShopUI : Control, IController
|
|||||||
if (playerGold >= _itemPrice)
|
if (playerGold >= _itemPrice)
|
||||||
{
|
{
|
||||||
// 发送购买命令
|
// 发送购买命令
|
||||||
this.SendCommand(new BuyItemCommand { ItemId = "sword_01" });
|
this.SendCommand(new BuyItemCommand("sword_01"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GD.Print("金币不足!");
|
Console.WriteLine("金币不足!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,11 +158,11 @@ public partial class ShopUI : Control, IController
|
|||||||
```csharp
|
```csharp
|
||||||
public class CombatSystem : AbstractSystem
|
public class CombatSystem : AbstractSystem
|
||||||
{
|
{
|
||||||
protected override void OnInit()
|
protected override void OnInit()
|
||||||
{
|
{
|
||||||
// 注册事件监听
|
// 注册事件监听
|
||||||
this.RegisterEvent<EnemyAttackEvent>(OnEnemyAttack);
|
this.RegisterEvent<EnemyAttackEvent>(OnEnemyAttack);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEnemyAttack(EnemyAttackEvent e)
|
private void OnEnemyAttack(EnemyAttackEvent e)
|
||||||
{
|
{
|
||||||
@ -173,12 +172,11 @@ this.RegisterEvent<EnemyAttackEvent>(OnEnemyAttack);
|
|||||||
if (!isDead)
|
if (!isDead)
|
||||||
{
|
{
|
||||||
// 执行伤害逻辑
|
// 执行伤害逻辑
|
||||||
this.SendCommand(new TakeDamageCommand { Damage = e.Damage });
|
this.SendCommand(new TakeDamageCommand(e.Damage));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
```
|
||||||
```
|
```
|
||||||
|
|
||||||
## 高级用法
|
## 高级用法
|
||||||
@ -189,22 +187,24 @@ this.RegisterEvent<EnemyAttackEvent>(OnEnemyAttack);
|
|||||||
// 查询指定范围内的敌人列表
|
// 查询指定范围内的敌人列表
|
||||||
public class GetEnemiesInRangeQuery : AbstractQuery<List<Enemy>>
|
public class GetEnemiesInRangeQuery : AbstractQuery<List<Enemy>>
|
||||||
{
|
{
|
||||||
public Vector3 Center { get; set; }
|
private readonly Vector3 _center;
|
||||||
public float Radius { get; set; }
|
private readonly float _radius;
|
||||||
|
|
||||||
|
public GetEnemiesInRangeQuery(Vector3 center, float radius)
|
||||||
|
{
|
||||||
|
_center = center;
|
||||||
|
_radius = radius;
|
||||||
|
}
|
||||||
|
|
||||||
protected override List<Enemy> OnDo()
|
protected override List<Enemy> OnDo()
|
||||||
{
|
{
|
||||||
var enemySystem = this.GetSystem<EnemySpawnSystem>();
|
var enemySystem = this.GetSystem<EnemySpawnSystem>();
|
||||||
return enemySystem.GetEnemiesInRange(Center, Radius);
|
return enemySystem.GetEnemiesInRange(_center, _radius);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用
|
// 使用
|
||||||
var enemies = this.SendQuery(new GetEnemiesInRangeQuery
|
var enemies = this.SendQuery(new GetEnemiesInRangeQuery(playerPosition, 10.0f));
|
||||||
{
|
|
||||||
Center = playerPosition,
|
|
||||||
Radius = 10.0f
|
|
||||||
});
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. 组合查询
|
### 2. 组合查询
|
||||||
@ -213,7 +213,12 @@ var enemies = this.SendQuery(new GetEnemiesInRangeQuery
|
|||||||
// 查询玩家是否可以使用技能
|
// 查询玩家是否可以使用技能
|
||||||
public class CanUseSkillQuery : AbstractQuery<bool>
|
public class CanUseSkillQuery : AbstractQuery<bool>
|
||||||
{
|
{
|
||||||
public string SkillId { get; set; }
|
private readonly string _skillId;
|
||||||
|
|
||||||
|
public CanUseSkillQuery(string skillId)
|
||||||
|
{
|
||||||
|
_skillId = skillId;
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool OnDo()
|
protected override bool OnDo()
|
||||||
{
|
{
|
||||||
@ -221,37 +226,44 @@ public string SkillId { get; set; }
|
|||||||
var skillModel = this.GetModel<SkillModel>();
|
var skillModel = this.GetModel<SkillModel>();
|
||||||
|
|
||||||
// 查询技能消耗
|
// 查询技能消耗
|
||||||
var skillCost = this.SendQuery(new GetSkillCostQuery { SkillId = SkillId });
|
var skillCost = this.SendQuery(new GetSkillCostQuery(_skillId));
|
||||||
|
|
||||||
// 检查是否满足条件
|
// 检查是否满足条件
|
||||||
return playerModel.Mana.Value >= skillCost.ManaCost
|
return playerModel.Mana.Value >= skillCost.ManaCost
|
||||||
&& !this.SendQuery(new IsSkillOnCooldownQuery { SkillId = SkillId });
|
&& !this.SendQuery(new IsSkillOnCooldownQuery(_skillId));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GetSkillCostQuery : AbstractQuery<SkillCost>
|
public class GetSkillCostQuery : AbstractQuery<SkillCost>
|
||||||
{
|
{
|
||||||
public string SkillId { get; set; }
|
private readonly string _skillId;
|
||||||
|
|
||||||
|
public GetSkillCostQuery(string skillId)
|
||||||
|
{
|
||||||
|
_skillId = skillId;
|
||||||
|
}
|
||||||
|
|
||||||
protected override SkillCost OnDo()
|
protected override SkillCost OnDo()
|
||||||
{
|
{
|
||||||
return this.GetModel<SkillModel>().GetSkillCost(SkillId);
|
return this.GetModel<SkillModel>().GetSkillCost(_skillId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class IsSkillOnCooldownQuery : AbstractQuery<bool>
|
public class IsSkillOnCooldownQuery : AbstractQuery<bool>
|
||||||
{
|
{
|
||||||
public string SkillId { get; set; }
|
private readonly string _skillId;
|
||||||
|
|
||||||
|
public IsSkillOnCooldownQuery(string skillId)
|
||||||
|
{
|
||||||
|
_skillId = skillId;
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool OnDo()
|
protected override bool OnDo()
|
||||||
{
|
{
|
||||||
return this.GetModel<SkillModel>().IsOnCooldown(SkillId);
|
return this.GetModel<SkillModel>().IsOnCooldown(_skillId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
```
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. 聚合数据查询
|
### 3. 聚合数据查询
|
||||||
@ -332,18 +344,38 @@ protected override void OnInit() { }
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Query 的执行机制
|
||||||
|
|
||||||
|
所有发送给查询总线的查询最终都会通过 `QueryExecutor` 来执行:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class QueryExecutor
|
||||||
|
{
|
||||||
|
public static TResult Execute<TResult>(IQuery<TResult> query)
|
||||||
|
{
|
||||||
|
return query.Do();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**特点:**
|
||||||
|
|
||||||
|
- 提供统一的查询执行机制
|
||||||
|
- 支持同步查询执行
|
||||||
|
- 与架构上下文集成
|
||||||
|
|
||||||
## Command vs Query
|
## Command vs Query
|
||||||
|
|
||||||
### Command(命令)
|
### Command(命令)
|
||||||
|
|
||||||
- **用途**:修改系统状态
|
- **用途**:修改系统状态
|
||||||
- **返回值**:无返回值(void)
|
- **返回值**:无返回值(void)或有返回值
|
||||||
- **示例**:购买物品、造成伤害、升级角色
|
- **示例**:购买物品、造成伤害、升级角色
|
||||||
|
|
||||||
### Query(查询)
|
### Query(查询)
|
||||||
|
|
||||||
- **用途**:读取数据,不修改状态
|
- **用途**:读取数据,不修改状态
|
||||||
- **返回值**:有返回值
|
- **返回值**:必须有返回值
|
||||||
- **示例**:获取金币数量、检查技能冷却、查询玩家位置
|
- **示例**:获取金币数量、检查技能冷却、查询玩家位置
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
@ -370,12 +402,17 @@ public class GoodQuery : AbstractQuery<int>
|
|||||||
// ✅ 修改数据应该使用 Command
|
// ✅ 修改数据应该使用 Command
|
||||||
public class AddGoldCommand : AbstractCommand
|
public class AddGoldCommand : AbstractCommand
|
||||||
{
|
{
|
||||||
public int Amount { get; set; }
|
private readonly int _amount;
|
||||||
|
|
||||||
|
public AddGoldCommand(int amount)
|
||||||
|
{
|
||||||
|
_amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnExecute()
|
protected override void OnExecute()
|
||||||
{
|
{
|
||||||
var model = this.GetModel<PlayerModel>();
|
var model = this.GetModel<PlayerModel>();
|
||||||
model.Gold.Value += Amount;
|
model.Gold.Value += _amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -387,6 +424,9 @@ public class AddGoldCommand : AbstractCommand
|
|||||||
3. **可组合** - 复杂查询可以通过组合简单查询实现
|
3. **可组合** - 复杂查询可以通过组合简单查询实现
|
||||||
4. **避免过度查询** - 如果需要频繁查询,考虑使用 BindableProperty
|
4. **避免过度查询** - 如果需要频繁查询,考虑使用 BindableProperty
|
||||||
5. **命名清晰** - Query 名称应该清楚表达查询意图(Get、Is、Can、Has等前缀)
|
5. **命名清晰** - Query 名称应该清楚表达查询意图(Get、Is、Can、Has等前缀)
|
||||||
|
6. **参数通过构造函数传递** - 查询需要的参数应在创建时传入
|
||||||
|
7. **查询无状态** - 查询不应该保存长期状态,执行完即可丢弃
|
||||||
|
8. **合理使用缓存** - 对于复杂计算,可以在 Model 中缓存结果
|
||||||
|
|
||||||
## 性能优化
|
## 性能优化
|
||||||
|
|
||||||
@ -396,7 +436,7 @@ public class AddGoldCommand : AbstractCommand
|
|||||||
// 在 Model 中缓存复杂计算
|
// 在 Model 中缓存复杂计算
|
||||||
public class PlayerModel : AbstractModel
|
public class PlayerModel : AbstractModel
|
||||||
{
|
{
|
||||||
private int? _cachedPower;
|
private int? _cachedPower;
|
||||||
|
|
||||||
public int GetPower()
|
public int GetPower()
|
||||||
{
|
{
|
||||||
@ -417,9 +457,8 @@ private int? _cachedPower;
|
|||||||
{
|
{
|
||||||
_cachedPower = null;
|
_cachedPower = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
```
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. 批量查询
|
### 2. 批量查询
|
||||||
@ -428,20 +467,46 @@ private int? _cachedPower;
|
|||||||
// 一次查询多个数据,而不是多次单独查询
|
// 一次查询多个数据,而不是多次单独查询
|
||||||
public class GetMultipleItemCountsQuery : AbstractQuery<Dictionary<string, int>>
|
public class GetMultipleItemCountsQuery : AbstractQuery<Dictionary<string, int>>
|
||||||
{
|
{
|
||||||
public List<string> ItemIds { get; set; }
|
private readonly List<string> _itemIds;
|
||||||
|
|
||||||
|
public GetMultipleItemCountsQuery(List<string> itemIds)
|
||||||
|
{
|
||||||
|
_itemIds = itemIds;
|
||||||
|
}
|
||||||
|
|
||||||
protected override Dictionary<string, int> OnDo()
|
protected override Dictionary<string, int> OnDo()
|
||||||
{
|
{
|
||||||
var inventory = this.GetModel<InventoryModel>();
|
var inventory = this.GetModel<InventoryModel>();
|
||||||
return ItemIds.ToDictionary(id => id, id => inventory.GetItemCount(id));
|
return _itemIds.ToDictionary(id => id, id => inventory.GetItemCount(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 查询模式优势
|
||||||
|
|
||||||
|
### 1. 职责分离
|
||||||
|
|
||||||
|
- 读写操作明确分离
|
||||||
|
- 便于优化读写性能
|
||||||
|
- 降低系统复杂度
|
||||||
|
|
||||||
|
### 2. 可扩展性
|
||||||
|
|
||||||
|
- 读写可以独立扩展
|
||||||
|
- 支持不同的数据存储策略
|
||||||
|
- 便于实现读写分离
|
||||||
|
|
||||||
|
### 3. 可维护性
|
||||||
|
|
||||||
|
- 查询逻辑集中管理
|
||||||
|
- 便于重构和优化
|
||||||
|
- 降低组件间耦合
|
||||||
|
|
||||||
## 相关包
|
## 相关包
|
||||||
|
|
||||||
- [`command`](./command.md) - CQRS 的命令部分
|
- [`command`](./command.md) - CQRS 的命令部分
|
||||||
- [`model`](./model.md) - Query 主要从 Model 获取数据
|
- [`model`](./model.md) - Query 主要从 Model 获取数据
|
||||||
- [`system`](./system.md) - System 中可以发送 Query
|
- [`system`](./system.md) - System 中可以发送 Query
|
||||||
- [`controller`](./controller.md) - Controller 中可以发送 Query
|
- [`controller`](./controller.md) - Controller 中可以发送 Query
|
||||||
- [`extensions`](./extensions.md) - 提供 SendQuery 扩展方法
|
- [`extensions`](./extensions.md) - 提供 SendQuery 扩展方法
|
||||||
|
- [`architecture`](./architecture.md) - 架构核心,负责查询的分发和执行
|
||||||
@ -4,9 +4,11 @@
|
|||||||
|
|
||||||
System 包定义了业务逻辑层(Business Logic Layer)。System 负责处理游戏的核心业务逻辑,协调 Model 之间的交互,响应事件并执行复杂的业务流程。
|
System 包定义了业务逻辑层(Business Logic Layer)。System 负责处理游戏的核心业务逻辑,协调 Model 之间的交互,响应事件并执行复杂的业务流程。
|
||||||
|
|
||||||
|
System 是 GFramework 架构中业务逻辑的核心组件,通过事件系统与 Model 和 Controller 进行通信。
|
||||||
|
|
||||||
## 核心接口
|
## 核心接口
|
||||||
|
|
||||||
### [`ICanGetSystem`](./system.md)
|
### ICanGetSystem
|
||||||
|
|
||||||
标记接口,表示该类型可以获取其他 System。
|
标记接口,表示该类型可以获取其他 System。
|
||||||
|
|
||||||
@ -16,7 +18,7 @@ System 包定义了业务逻辑层(Business Logic Layer)。System 负责处
|
|||||||
public interface ICanGetSystem : IBelongToArchitecture
|
public interface ICanGetSystem : IBelongToArchitecture
|
||||||
```
|
```
|
||||||
|
|
||||||
### [`ISystem`](./system.md)
|
### ISystem
|
||||||
|
|
||||||
System 接口,定义了系统的基本行为。
|
System 接口,定义了系统的基本行为。
|
||||||
|
|
||||||
@ -30,7 +32,10 @@ void OnArchitecturePhase(ArchitecturePhase phase); // 处理架构阶段事件
|
|||||||
|
|
||||||
**继承的能力:**
|
**继承的能力:**
|
||||||
|
|
||||||
- `ICanSetArchitecture` - 可设置架构
|
- `IContextAware` - 上下文感知
|
||||||
|
- `IInitializable` - 可初始化
|
||||||
|
- `IDisposable` - 可销毁
|
||||||
|
- `IArchitecturePhaseAware` - 架构阶段感知
|
||||||
- `ICanGetModel` - 可获取 Model
|
- `ICanGetModel` - 可获取 Model
|
||||||
- `ICanGetUtility` - 可获取 Utility
|
- `ICanGetUtility` - 可获取 Utility
|
||||||
- `ICanGetSystem` - 可获取其他 System
|
- `ICanGetSystem` - 可获取其他 System
|
||||||
@ -39,33 +44,57 @@ void OnArchitecturePhase(ArchitecturePhase phase); // 处理架构阶段事件
|
|||||||
|
|
||||||
## 核心类
|
## 核心类
|
||||||
|
|
||||||
### [`AbstractSystem`](./system.md)
|
### AbstractSystem
|
||||||
|
|
||||||
抽象 System 基类,提供了 System 的基础实现。继承自 ContextAwareBase,具有上下文感知能力。
|
抽象 System 基类,提供了 System 的基础实现。继承自 ContextAwareBase,具有上下文感知能力。
|
||||||
|
|
||||||
|
**核心方法:**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
void IInitializable.Init(); // 实现初始化接口
|
||||||
|
void IDisposable.Destroy(); // 实现销毁接口
|
||||||
|
protected abstract void OnInit(); // 抽象初始化方法,由子类实现
|
||||||
|
protected virtual void OnDestroy(); // 虚拟销毁方法,子类可重写
|
||||||
|
public virtual void OnArchitecturePhase(ArchitecturePhase phase); // 处理架构阶段事件
|
||||||
|
```
|
||||||
|
|
||||||
**使用方式:**
|
**使用方式:**
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public abstract class AbstractSystem : ContextAwareBase, ISystem
|
public abstract class AbstractSystem : ContextAwareBase, ISystem
|
||||||
{
|
{
|
||||||
void ISystem.Init() => OnInit(); // 系统初始化,内部调用抽象方法 OnInit()
|
void IInitializable.Init() => OnInit(); // 系统初始化,内部调用抽象方法 OnInit()
|
||||||
void ISystem.Destroy() => OnDestroy(); // 系统销毁,内部调用 OnDestroy()
|
void IDisposable.Destroy() => OnDestroy(); // 系统销毁,内部调用 OnDestroy()
|
||||||
protected abstract void OnInit(); // 子类实现初始化逻辑
|
protected abstract void OnInit(); // 子类实现初始化逻辑
|
||||||
protected virtual void OnDestroy(); // 子类可选择重写销毁逻辑
|
protected virtual void OnDestroy(); // 子类可选择重写销毁逻辑
|
||||||
public virtual void OnArchitecturePhase(ArchitecturePhase phase); // 处理架构阶段事件
|
public virtual void OnArchitecturePhase(ArchitecturePhase phase); // 处理架构阶段事件
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## System 生命周期
|
||||||
|
|
||||||
|
System 的生命周期由架构管理:
|
||||||
|
|
||||||
|
1. **注册阶段**:通过 `architecture.RegisterSystem()` 注册到架构
|
||||||
|
2. **初始化阶段**:架构调用 `Init()` 方法,内部执行 `OnInit()`
|
||||||
|
3. **运行阶段**:处理事件和执行业务逻辑
|
||||||
|
4. **销毁阶段**:架构调用 `Destroy()` 方法,内部执行 `OnDestroy()`
|
||||||
|
|
||||||
## 基本使用
|
## 基本使用
|
||||||
|
|
||||||
### 1. 定义 System
|
### 1. 定义 System
|
||||||
|
|
||||||
```
|
```csharp
|
||||||
// 战斗系统
|
// 战斗系统
|
||||||
public class CombatSystem : AbstractSystem
|
public class CombatSystem : AbstractSystem
|
||||||
{
|
{
|
||||||
|
private ILogger _logger;
|
||||||
|
|
||||||
protected override void OnInit()
|
protected override void OnInit()
|
||||||
{
|
{
|
||||||
|
_logger = this.GetUtility<ILogger>();
|
||||||
|
_logger.Info("CombatSystem initialized");
|
||||||
|
|
||||||
// 注册事件监听
|
// 注册事件监听
|
||||||
this.RegisterEvent<EnemyAttackEvent>(OnEnemyAttack);
|
this.RegisterEvent<EnemyAttackEvent>(OnEnemyAttack);
|
||||||
this.RegisterEvent<PlayerAttackEvent>(OnPlayerAttack);
|
this.RegisterEvent<PlayerAttackEvent>(OnPlayerAttack);
|
||||||
@ -83,6 +112,8 @@ public class CombatSystem : AbstractSystem
|
|||||||
|
|
||||||
// 发送伤害事件
|
// 发送伤害事件
|
||||||
this.SendEvent(new PlayerTookDamageEvent { Damage = damage });
|
this.SendEvent(new PlayerTookDamageEvent { Damage = damage });
|
||||||
|
|
||||||
|
_logger.Debug($"Player took {damage} damage from enemy attack");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPlayerAttack(PlayerAttackEvent e)
|
private void OnPlayerAttack(PlayerAttackEvent e)
|
||||||
@ -98,6 +129,8 @@ public class CombatSystem : AbstractSystem
|
|||||||
EnemyId = e.Enemy.Id,
|
EnemyId = e.Enemy.Id,
|
||||||
Damage = damage
|
Damage = damage
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_logger.Debug($"Enemy {e.Enemy.Id} took {damage} damage from player attack");
|
||||||
}
|
}
|
||||||
|
|
||||||
private int CalculateDamage(int attackPower, int defense)
|
private int CalculateDamage(int attackPower, int defense)
|
||||||
@ -107,34 +140,50 @@ public class CombatSystem : AbstractSystem
|
|||||||
|
|
||||||
protected override void OnDestroy()
|
protected override void OnDestroy()
|
||||||
{
|
{
|
||||||
|
_logger.Info("CombatSystem destroyed");
|
||||||
// 清理资源
|
// 清理资源
|
||||||
base.OnDestroy();
|
base.OnDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnArchitecturePhase(ArchitecturePhase phase)
|
||||||
|
{
|
||||||
|
switch (phase)
|
||||||
|
{
|
||||||
|
case ArchitecturePhase.AfterSystemInit:
|
||||||
|
_logger.Info("CombatSystem is ready");
|
||||||
|
break;
|
||||||
|
case ArchitecturePhase.Destroying:
|
||||||
|
_logger.Info("CombatSystem is shutting down");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. 注册 System
|
### 2. 注册 System
|
||||||
|
|
||||||
```
|
```csharp
|
||||||
public class GameArchitecture : Architecture
|
public class GameArchitecture : Architecture
|
||||||
{
|
{
|
||||||
protected override void Init()
|
protected override void Init()
|
||||||
{
|
{
|
||||||
// 注册 Model
|
// 注册 Model
|
||||||
this.RegisterModel<PlayerModel>(new PlayerModel());
|
this.RegisterModel(new PlayerModel());
|
||||||
this.RegisterModel<EnemyModel>(new EnemyModel());
|
this.RegisterModel(new EnemyModel());
|
||||||
|
this.RegisterModel(new InventoryModel());
|
||||||
|
|
||||||
// 注册 System(系统注册后会自动调用 Init)
|
// 注册 System(系统注册后会自动调用 Init)
|
||||||
this.RegisterSystem<CombatSystem>(new CombatSystem());
|
this.RegisterSystem(new CombatSystem());
|
||||||
this.RegisterSystem<InventorySystem>(new InventorySystem());
|
this.RegisterSystem(new InventorySystem());
|
||||||
this.RegisterSystem<QuestSystem>(new QuestSystem());
|
this.RegisterSystem(new QuestSystem());
|
||||||
|
this.RegisterSystem(new UISystem());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. 在其他组件中获取 System
|
### 3. 在其他组件中获取 System
|
||||||
|
|
||||||
```
|
```csharp
|
||||||
// 在 Controller 中
|
// 在 Controller 中
|
||||||
public partial class GameController : Node, IController
|
public partial class GameController : Node, IController
|
||||||
{
|
{
|
||||||
@ -145,6 +194,9 @@ public partial class GameController : Node, IController
|
|||||||
// 获取 System
|
// 获取 System
|
||||||
var combatSystem = this.GetSystem<CombatSystem>();
|
var combatSystem = this.GetSystem<CombatSystem>();
|
||||||
var questSystem = this.GetSystem<QuestSystem>();
|
var questSystem = this.GetSystem<QuestSystem>();
|
||||||
|
|
||||||
|
// 使用 System
|
||||||
|
combatSystem.StartBattle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +206,17 @@ public class StartBattleCommand : AbstractCommand
|
|||||||
protected override void OnExecute()
|
protected override void OnExecute()
|
||||||
{
|
{
|
||||||
var combatSystem = this.GetSystem<CombatSystem>();
|
var combatSystem = this.GetSystem<CombatSystem>();
|
||||||
// 使用 System...
|
combatSystem.StartBattle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在其他 System 中
|
||||||
|
public class AISystem : AbstractSystem
|
||||||
|
{
|
||||||
|
protected override void OnInit()
|
||||||
|
{
|
||||||
|
var combatSystem = this.GetSystem<CombatSystem>();
|
||||||
|
// 与其他 System 协作
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user