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