From 6b48c92710a041a49262fdd0b9d7a4917b9f177f Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:14:44 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=88=A0=E9=99=A4=E5=A4=9A=E4=B8=AA?= =?UTF-8?q?=E6=A0=B8=E5=BF=83=E6=A8=A1=E5=9D=97=E7=9A=84=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除 architecture 模块的 README 文档 - 移除 command 模块的 README 文档 - 移除 environment 模块的 README 文档 - 移除 events 模块的 README 文档 - 清理框架核心组件的使用说明文档 --- GFramework.Core.Abstractions/README.md | 533 +--------- .../controller/README.md | 413 -------- GFramework.Core/README.md | 31 + GFramework.Core/architecture/README.md | 509 ---------- GFramework.Core/command/README.md | 309 ------ GFramework.Core/environment/README.md | 218 ---- GFramework.Core/events/README.md | 524 ---------- GFramework.Core/extensions/README.md | 552 ---------- GFramework.Core/ioc/README.md | 689 ------------- GFramework.Core/logging/README.md | 364 ------- GFramework.Core/model/README.md | 184 ---- GFramework.Core/pool/README.md | 951 ------------------ GFramework.Core/property/README.md | 341 ------- GFramework.Core/query/README.md | 447 -------- GFramework.Core/rule/README.md | 316 ------ GFramework.Core/system/README.md | 544 ---------- GFramework.Core/utility/README.md | 613 ----------- GFramework.Game.Abstractions/README.md | 11 +- GFramework.Game/README.md | 16 + GFramework.Game/setting/README.md | 204 ---- GFramework.Godot.SourceGenerators/README.md | 9 +- GFramework.Godot/README.md | 19 + GFramework.Godot/extensions/README.md | 335 ------ GFramework.Godot/extensions/signal/README.md | 427 -------- GFramework.Godot/setting/README.md | 579 ----------- GFramework.Godot/storage/README.md | 281 ------ 26 files changed, 94 insertions(+), 9325 deletions(-) delete mode 100644 GFramework.Core.Abstractions/controller/README.md create mode 100644 GFramework.Core/README.md delete mode 100644 GFramework.Core/architecture/README.md delete mode 100644 GFramework.Core/command/README.md delete mode 100644 GFramework.Core/environment/README.md delete mode 100644 GFramework.Core/events/README.md delete mode 100644 GFramework.Core/extensions/README.md delete mode 100644 GFramework.Core/ioc/README.md delete mode 100644 GFramework.Core/logging/README.md delete mode 100644 GFramework.Core/model/README.md delete mode 100644 GFramework.Core/pool/README.md delete mode 100644 GFramework.Core/property/README.md delete mode 100644 GFramework.Core/query/README.md delete mode 100644 GFramework.Core/rule/README.md delete mode 100644 GFramework.Core/system/README.md delete mode 100644 GFramework.Core/utility/README.md create mode 100644 GFramework.Game/README.md delete mode 100644 GFramework.Game/setting/README.md create mode 100644 GFramework.Godot/README.md delete mode 100644 GFramework.Godot/extensions/README.md delete mode 100644 GFramework.Godot/extensions/signal/README.md delete mode 100644 GFramework.Godot/setting/README.md delete mode 100644 GFramework.Godot/storage/README.md diff --git a/GFramework.Core.Abstractions/README.md b/GFramework.Core.Abstractions/README.md index 812cba2..dce62d6 100644 --- a/GFramework.Core.Abstractions/README.md +++ b/GFramework.Core.Abstractions/README.md @@ -1,521 +1,26 @@ -# GFramework.Core.Abstractions 抽象层 +# GFramework.Core.Abstractions -> GFramework 框架的接口定义模块,提供所有核心组件的抽象契约 +GFramework 框架的抽象层定义模块,包含所有核心组件的接口定义。 -## 概述 +## 主要内容 -GFramework.Core.Abstractions 是 GFramework 框架的抽象层定义模块,包含了框架中所有核心组件的接口(Interface)、枚举(Enum)和配置类(Class)。该模块采用 -`netstandard2.0` 作为目标框架,确保了广泛的兼容性和可移植性。 +- 架构核心接口 (IArchitecture, IArchitectureContext等) +- 数据模型接口 (IModel) +- 业务系统接口 (ISystem) +- 控制器接口 (IController) +- 命令与查询接口 (ICommand, IQuery) +- 事件系统接口 (IEvent, IEventBus) +- 依赖注入容器接口 (IIocContainer) +- 可绑定属性接口 (IBindableProperty) +- 日志系统接口 (ILogger) -本模块遵循以下设计原则: +## 设计原则 -- **接口隔离**:每个接口职责单一,便于实现和测试 -- **依赖倒置**:上层模块依赖抽象接口,而非具体实现 -- **组合优于继承**:通过接口组合获得能力,而非通过继承获得 -- **类型安全**:充分利用泛型系统确保类型安全 +- 接口隔离,每个接口职责单一 +- 依赖倒置,上层依赖抽象接口 +- 类型安全,充分利用泛型系统 +- 广泛兼容,基于 netstandard2.0 -本模块的包 ID 为 `GeWuYou.GFramework.Core.Abstractions`,遵循命名空间 `GFramework.Core.Abstractions` 下的所有定义。 +## 详细文档 -## 目录结构 - -``` -GFramework.Core.Abstractions/ -├── architecture/ # 架构核心接口 -│ ├── IArchitecture.cs -│ ├── IArchitectureConfiguration.cs -│ ├── IArchitectureContext.cs -│ ├── IArchitectureLifecycle.cs -│ ├── IArchitectureModule.cs -│ ├── IArchitecturePhaseAware.cs -│ ├── IArchitectureServices.cs -│ └── IAsyncInitializable.cs -├── command/ # 命令模式接口 -│ ├── ICommand.cs -│ ├── ICommandBus.cs -│ └── ICommandInput.cs -├── controller/ # 控制器接口 -│ └── IController.cs -├── enums/ # 枚举定义 -│ └── ArchitecturePhase.cs -├── environment/ # 环境接口 -│ └── IEnvironment.cs -├── events/ # 事件系统接口 -│ ├── IEasyEvent.cs -│ ├── ITypeEventSystem.cs -│ ├── IUnRegister.cs -│ └── IUnRegisterList.cs -├── ioc/ # 依赖注入容器接口 -│ └── IIocContainer.cs -├── logging/ # 日志系统接口 -│ ├── ILogger.cs -│ ├── ILoggerFactory.cs -│ ├── ILoggerFactoryProvider.cs -│ └── LogLevel.cs -├── model/ # 模型接口 -│ └── IModel.cs -├── properties/ # 配置类 -│ ├── ArchitectureProperties.cs -│ └── LoggerProperties.cs -├── property/ # 可绑定属性接口 -│ ├── IBindableProperty.cs -│ └── IReadonlyBindableProperty.cs -├── query/ # 查询模式接口 -│ ├── IQuery.cs -│ ├── IQueryBus.cs -│ └── IQueryInput.cs -├── rule/ # 规则接口 -│ ├── IContextAware.cs -│ └── ILogAware.cs -├── system/ # 系统接口 -│ └── ISystem.cs -└── utility/ # 工具接口 - ├── IContextUtility.cs - └── IUtility.cs -``` - -## 模块说明 - -### 1. architecture(架构核心) - -架构模块是整个框架的核心,定义了应用架构的生命周期管理和组件注册机制。该模块包含以下接口: - -#### [`IArchitecture`](architecture/IArchitecture.cs) - -架构接口是整个应用的核心管理器,负责管理系统、模型和工具类的注册与获取。它继承自 [ -`IAsyncInitializable`](architecture/IAsyncInitializable.cs) 接口,支持异步初始化。该接口提供了注册系统([ -`RegisterSystem`](architecture/IArchitecture.cs#L39))、注册模型([ -`RegisterModel`](architecture/IArchitecture.cs#L46))、注册工具([ -`RegisterUtility`](architecture/IArchitecture.cs#L53))的方法,以及安装模块([ -`InstallModule`](architecture/IArchitecture.cs#L59))和注册生命周期钩子([ -`RegisterLifecycleHook`](architecture/IArchitecture.cs#L65))的功能。 - -#### [`IArchitectureContext`](architecture/IArchitectureContext.cs) - -架构上下文接口提供了对已注册组件的访问能力,是组件之间通信的桥梁。通过该接口,可以获取系统([ -`GetSystem`](architecture/IArchitectureContext.cs#L22))、模型([ -`GetModel`](architecture/IArchitectureContext.cs#L29))和工具([ -`GetUtility`](architecture/IArchitectureContext.cs#L36))实例。同时,该接口还支持发送命令([ -`SendCommand`](architecture/IArchitectureContext.cs#L42))、发送查询([ -`SendQuery`](architecture/IArchitectureContext.cs#L58))和发送事件([ -`SendEvent`](architecture/IArchitectureContext.cs#L64))等横切操作。 - -#### [`IArchitectureConfiguration`](architecture/IArchitectureConfiguration.cs) - -架构配置接口定义了框架的配置选项,包括日志配置([`LoggerProperties`](architecture/IArchitectureConfiguration.cs#L13) -)和架构配置([`ArchitectureProperties`](architecture/IArchitectureConfiguration.cs#L18) -)。通过该接口,可以在运行时调整框架的行为,如设置日志级别、启用延迟注册等。 - -#### [`IArchitectureLifecycle`](architecture/IArchitectureLifecycle.cs) - -架构生命周期接口定义了架构在不同阶段的回调方法。当架构进入特定阶段时,会通知所有注册的生命周期监听器。该接口主要用于模块化架构的阶段感知。 - -#### [`IArchitectureModule`](architecture/IArchitectureModule.cs) - -架构模块接口继承自 [`IArchitectureLifecycle`](architecture/IArchitectureLifecycle.cs) 和 [ -`IArchitecturePhaseAware`](architecture/IArchitecturePhaseAware.cs) 接口,定义了模块安装到架构的标准方法([ -`Install`](architecture/IArchitectureModule.cs#L13))。通过模块化机制,可以将复杂功能封装为可插拔的模块。 - -#### [`IArchitecturePhaseAware`](architecture/IArchitecturePhaseAware.cs) - -架构阶段感知接口允许组件在架构的不同阶段执行相应的逻辑。该接口提供了 [ -`OnArchitecturePhase`](architecture/IArchitecturePhaseAware.cs#L14) 方法,当架构进入指定阶段时会被调用。 - -#### [`IArchitectureServices`](architecture/IArchitectureServices.cs) - -架构服务接口定义了框架核心服务组件,继承自 [`IContextAware`](rule/IContextAware.cs) 接口。该接口提供了依赖注入容器([ -`Container`](architecture/IArchitectureServices.cs#L18))、类型事件系统([ -`TypeEventSystem`](architecture/IArchitectureServices.cs#L24))、命令总线([ -`CommandBus`](architecture/IArchitectureServices.cs#L29))和查询总线([ -`QueryBus`](architecture/IArchitectureServices.cs#L34))的访问能力。 - -#### [`IAsyncInitializable`](architecture/IAsyncInitializable.cs) - -异步初始化接口定义了组件的异步初始化方法([`InitializeAsync`](architecture/IAsyncInitializable.cs#L14) -)。该接口用于需要执行异步初始化操作的组件,如加载资源、建立网络连接等。 - -### 2. command(命令模式) - -命令模块实现了命令查询职责分离模式(CQRS)中的命令部分,用于封装写操作。该模块包含以下接口: - -#### [`ICommand`](command/ICommand.cs) - -命令接口定义了无返回值命令的基本契约,继承自 [`IContextAware`](rule/IContextAware.cs) 接口。该接口提供了命令执行方法([ -`Execute`](command/ICommand.cs#L15)),用于执行具体的业务逻辑。带返回值的命令由泛型接口 [ -`ICommand`](command/ICommand.cs#L23) 定义,同样继承自 [`IContextAware`](rule/IContextAware.cs) 接口。 - -#### [`ICommandBus`](command/ICommandBus.cs) - -命令总线接口负责命令的发送和执行调度。该接口提供了发送无返回值命令([`Send`](command/ICommandBus.cs#L12) -)和发送带返回值命令([`Send`](command/ICommandBus.cs#L20))的方法。 - -#### [`ICommandInput`](command/ICommandInput.cs) - -命令输入接口是命令模式中输入数据的标记接口,不包含任何成员定义。该接口用于规范化命令的输入参数类型。 - -### 3. controller(控制器) - -控制器模块定义了表现层与业务逻辑层之间的桥梁接口。 - -#### [`IController`](controller/IController.cs) - -控制器接口是 MVC 架构中控制层的抽象定义。该接口作为标记接口使用,不包含任何方法定义,但实现该接口的类通常会获得访问架构上下文的能力,从而可以发送命令、查询数据、注册事件等。 - -### 4. enums(枚举定义) - -枚举模块定义了框架中使用的枚举类型。 - -#### [`ArchitecturePhase`](enums/ArchitecturePhase.cs) - -架构阶段枚举定义了系统架构初始化和运行过程中的各个关键阶段。按照初始化流程,依次包括:`None`(无效阶段)、`BeforeUtilityInit` -(工具类初始化之前)、`AfterUtilityInit`(工具类初始化之后)、`BeforeModelInit`(模型初始化之前)、`AfterModelInit`(模型初始化之后)、 -`BeforeSystemInit`(系统初始化之前)、`AfterSystemInit`(系统初始化之后)、`Ready`(就绪阶段),以及销毁相关阶段:`Destroying` -(正在销毁中)、`Destroyed`(已销毁)、`FailedInitialization`(初始化失败)。 - -### 5. environment(环境接口) - -环境模块定义了应用程序运行环境的抽象接口。 - -#### [`IEnvironment`](environment/IEnvironment.cs) - -环境接口提供了获取应用程序运行环境相关信息的能力。该接口支持根据键值获取配置值([ -`Get`](environment/IEnvironment.cs#L20))、尝试获取环境值([`TryGet`](environment/IEnvironment.cs#L29) -)、获取必需的环境值([`GetRequired`](environment/IEnvironment.cs#L37)),以及注册键值对([ -`Register`](environment/IEnvironment.cs#L44))和初始化环境([`Initialize`](environment/IEnvironment.cs#L49))。 - -### 6. events(事件系统) - -事件模块实现了框架的事件驱动通信机制,支持类型安全和松耦合的组件通信。 - -#### [`ITypeEventSystem`](events/ITypeEventSystem.cs) - -类型事件系统接口是基于类型的事件发布-订阅机制的抽象定义。该接口支持发送无参事件([ -`Send`](events/ITypeEventSystem.cs#L14))、发送带参事件([`Send`](events/ITypeEventSystem.cs#L21))、注册事件监听器([ -`Register`](events/ITypeEventSystem.cs#L29))和注销事件监听器([`UnRegister`](events/ITypeEventSystem.cs#L36))。 - -#### [`IEasyEvent`](events/IEasyEvent.cs) - -简单事件接口定义了基础的事件注册功能([`Register`](events/IEasyEvent.cs#L15))。该接口用于简单的无参事件场景。 - -#### [`IUnRegister`](events/IUnRegister.cs) - -注销接口提供了事件监听器的注销功能([`UnRegister`](events/IUnRegister.cs#L11))。所有事件注册方法的返回值都实现了该接口,用于在适当时机取消事件监听。 - -#### [`IUnRegisterList`](events/IUnRegisterList.cs) - -统一注销接口提供了管理多个注销句柄的能力。该接口维护了一个注销对象列表([`UnregisterList`](events/IUnRegisterList.cs#L13) -),可以在批量注销时统一处理。 - -### 7. ioc(依赖注入) - -IoC 模块实现了控制反转和依赖注入机制,用于管理组件的生命周期和依赖关系。 - -#### [`IIocContainer`](ioc/IIocContainer.cs) - -依赖注入容器接口是框架的核心服务接口之一,继承自 [`IContextAware`](rule/IContextAware.cs) -接口。该接口提供了丰富的服务注册和解析方法,包括注册单例([`RegisterSingleton`](ioc/IIocContainer.cs#L22) -)、注册多个实例([`RegisterPlurality`](ioc/IIocContainer.cs#L30))、注册系统([`RegisterSystem`](ioc/IIocContainer.cs#L36) -)、注册类型([`Register`](ioc/IIocContainer.cs#L43))等。在解析方面,支持获取单个实例([`Get`](ioc/IIocContainer.cs#L62) -)、获取必需实例([`GetRequired`](ioc/IIocContainer.cs#L70))、获取所有实例([`GetAll`](ioc/IIocContainer.cs#L77) -)和获取排序后的实例([`GetAllSorted`](ioc/IIocContainer.cs#L85))。此外,还提供了检查([ -`Contains`](ioc/IIocContainer.cs#L96))、清空([`Clear`](ioc/IIocContainer.cs#L108))和冻结([ -`Freeze`](ioc/IIocContainer.cs#L113))等实用方法。 - -### 8. logging(日志系统) - -日志模块提供了完整的日志记录抽象,支持多级别日志输出。 - -#### [`LogLevel`](logging/LogLevel.cs) - -日志级别枚举定义了日志消息的严重程度等级,包括:`Trace`(跟踪级别,用于详细的程序执行流程信息)、`Debug`(调试级别,用于调试过程中的详细信息)、 -`Info`(信息级别,用于一般性的程序运行信息)、`Warning`(警告级别,用于表示可能的问题或异常情况)、`Error` -(错误级别,用于表示错误但程序仍可继续运行的情况)、`Fatal`(致命级别,用于表示严重的错误导致程序无法继续运行)。 - -#### [`ILogger`](logging/ILogger.cs) - -日志记录器接口是框架日志系统的核心接口,提供了完整的日志记录能力。该接口支持以下功能: - -- **级别启用检查**:提供了各个日志级别的是否启用检查方法,如 [`IsTraceEnabled`](logging/ILogger.cs#L22)、[ - `IsDebugEnabled`](logging/ILogger.cs#L28)、[`IsInfoEnabled`](logging/ILogger.cs#L34)、[ - `IsWarnEnabled`](logging/ILogger.cs#L40)、[`IsErrorEnabled`](logging/ILogger.cs#L46)、[ - `IsFatalEnabled`](logging/ILogger.cs#L52),以及通用的 [`IsEnabledForLevel`](logging/ILogger.cs#L59) 方法。 -- **日志记录方法**:每个日志级别都有多种重载形式,支持简单消息、格式化消息和异常记录。格式化为 `Trace`、`Debug`、`Info`、 - `Warn`、`Error`、`Fatal` 六个级别,每个级别都提供了 `msg`、`format+arg`、`format+arg1+arg2`、`format+params`、`msg+exception` - 等多种调用方式。 -- **获取日志记录器名称**:通过 [`Name`](logging/ILogger.cs#L14) 方法获取日志记录器的名称。 - -#### [`ILoggerFactory`](logging/ILoggerFactory.cs) - -日志工厂接口用于创建日志记录器实例([`GetLogger`](logging/ILoggerFactory.cs#L14))。该接口支持指定日志记录器名称和最小日志级别。 - -#### [`ILoggerFactoryProvider`](logging/ILoggerFactoryProvider.cs) - -日志工厂提供者接口扩展了日志工厂的功能,支持动态设置最小日志级别([`MinLevel`](logging/ILoggerFactoryProvider.cs#L11) -)和创建日志记录器([`CreateLogger`](logging/ILoggerFactoryProvider.cs#L18))。 - -### 9. model(模型接口) - -模型模块定义了数据层的抽象接口。 - -#### [`IModel`](model/IModel.cs) - -模型接口继承自 [`IContextAware`](rule/IContextAware.cs) 和 [ -`IArchitecturePhaseAware`](architecture/IArchitecturePhaseAware.cs) -接口,定义了模型组件的基本行为。该接口提供了模型初始化方法([`Init`](model/IModel.cs#L14)),用于执行模型相关的初始化逻辑。 - -### 10. properties(配置类) - -配置模块定义了框架使用的配置选项类。 - -#### [`LoggerProperties`](properties/LoggerProperties.cs) - -日志配置选项类用于配置日志系统的相关参数,包含日志工厂提供程序属性([ -`LoggerFactoryProvider`](properties/LoggerProperties.cs#L14))。 - -#### [`ArchitectureProperties`](properties/ArchitectureProperties.cs) - -架构选项配置类用于定义架构行为的相关配置选项,包含两个属性:`AllowLateRegistration`(允许延迟注册开关,控制是否允许在初始化完成后进行组件注册)和 -`StrictPhaseValidation`(严格阶段验证开关,控制是否启用严格的阶段验证机制)。 - -### 11. property(可绑定属性) - -可绑定属性模块实现了响应式数据绑定机制,支持数据变化的自动通知。 - -#### [`IReadonlyBindableProperty`](property/IReadonlyBindableProperty.cs) - -只读可绑定属性接口继承自 [`IEasyEvent`](events/IEasyEvent.cs) -接口,提供了属性值的读取和变更监听功能。该接口支持获取当前值([`Value`](property/IReadonlyBindableProperty.cs#L15) -)、注册带初始值的回调([`RegisterWithInitValue`](property/IReadonlyBindableProperty.cs#L22))、取消注册回调([ -`UnRegister`](property/IReadonlyBindableProperty.cs#L28))和注册回调([ -`Register`](property/IReadonlyBindableProperty.cs#L35))。 - -#### [`IBindableProperty`](property/IBindableProperty.cs) - -可绑定属性接口继承自只读可绑定属性接口,提供了可读写的属性绑定功能。该接口在只读接口的基础上增加了属性值的设置能力([ -`Value`](property/IBindableProperty.cs#L12) 的 setter)以及不触发事件的设置方法([ -`SetValueWithoutEvent`](property/IBindableProperty.cs#L18))。 - -### 12. query(查询模式) - -查询模块实现了命令查询职责分离模式(CQRS)中的查询部分,用于封装读操作。 - -#### [`IQuery`](query/IQuery.cs) - -查询接口继承自 [`IContextAware`](rule/IContextAware.cs) 接口,定义了执行查询操作的契约。该接口提供了查询执行方法([ -`Do`](query/IQuery.cs#L15)),返回指定类型的结果。 - -#### [`IQueryBus`](query/IQueryBus.cs) - -查询总线接口负责查询的发送和执行调度。该接口提供了发送查询并返回结果的方法([`Send`](query/IQueryBus.cs#L14))。 - -#### [`IQueryInput`](query/IQueryInput.cs) - -查询输入接口是查询模式中输入数据的标记接口,不包含任何成员定义。 - -### 13. rule(规则接口) - -规则模块定义了框架组件需要遵循的约束和规则接口。 - -#### [`IContextAware`](rule/IContextAware.cs) - -上下文感知接口允许实现类设置和获取架构上下文。该接口提供了设置上下文([`SetContext`](rule/IContextAware.cs#L14) -)和获取上下文([`GetContext`](rule/IContextAware.cs#L20))的方法。框架中大多数核心组件(如命令、查询、系统、模型、工具、IoC -容器等)都实现了该接口,以获得访问架构服务的能力。 - -#### [`ILogAware`](rule/ILogAware.cs) - -日志感知接口允许实现类设置和使用日志记录器。该接口提供了设置日志记录器的方法([`SetLogger`](rule/ILogAware.cs#L14))。 - -### 14. system(系统接口) - -系统模块定义了业务逻辑层的抽象接口。 - -#### [`ISystem`](system/ISystem.cs) - -系统接口继承自 [`IContextAware`](rule/IContextAware.cs) 和 [ -`IArchitecturePhaseAware`](architecture/IArchitecturePhaseAware.cs) -接口,定义了系统组件的基本行为。该接口提供了系统初始化方法([`Init`](system/ISystem.cs#L16))和系统销毁方法([ -`Destroy`](system/ISystem.cs#L22)),用于管理系统的生命周期。 - -### 15. utility(工具接口) - -工具模块定义了无状态工具类的抽象接口。 - -#### [`IUtility`](utility/IUtility.cs) - -工具接口是所有工具类实现的基础接口,作为标记接口使用,不包含任何成员定义。该接口定义了通用工具类的基本契约。 - -#### [`IContextUtility`](utility/IContextUtility.cs) - -上下文工具接口继承自 [`IUtility`](utility/IUtility.cs) 和 [`IContextAware`](rule/IContextAware.cs) -接口,提供了具有上下文感知能力的工具功能。该接口在工具接口的基础上增加了初始化方法([ -`Init`](utility/IContextUtility.cs#L14))。 - -## 接口继承关系图 - -``` -IArchitecture - └── IAsyncInitializable - -IArchitectureModule - ├── IArchitectureLifecycle - └── IArchitecturePhaseAware - -IArchitectureServices - └── IContextAware - -ICommand - └── IContextAware - -ICommand - └── IContextAware - -IIocContainer - └── IContextAware - -IQuery - └── IContextAware - -IModel - ├── IContextAware - └── IArchitecturePhaseAware - -ISystem - ├── IContextAware - └── IArchitecturePhaseAware - -IContextUtility - ├── IUtility - └── IContextAware - -IReadonlyBindableProperty - └── IEasyEvent - -IBindableProperty - └── IReadonlyBindableProperty -``` - -## 核心能力接口 - -框架中的组件通过实现特定的接口来获得相应的能力。这些能力接口主要分为以下几类: - -### 上下文感知能力 - -通过实现 [`IContextAware`](rule/IContextAware.cs) 接口,组件可以获得设置和获取架构上下文的能力,从而访问框架提供的各种服务。命令、查询、系统、模型、工具、IoC -容器等核心组件都实现了该接口。 - -### 日志能力 - -通过实现 [`ILogAware`](rule/ILogAware.cs) 接口,组件可以获得使用日志记录器的能力。该接口提供了设置日志记录器的方法,使组件可以输出日志信息。 - -### 阶段感知能力 - -通过实现 [`IArchitecturePhaseAware`](architecture/IArchitecturePhaseAware.cs) -接口,组件可以在架构的不同阶段执行相应的逻辑。该接口提供了 [ -`OnArchitecturePhase`](architecture/IArchitecturePhaseAware.cs#L14) 方法,当架构进入指定阶段时会被调用。 - -## 使用指南 - -### 实现框架组件 - -当需要实现框架的组件时,通常需要实现相应的接口并遵循框架的生命周期约定: - -```csharp -// 实现系统组件 -public class CombatSystem : ISystem -{ - public void Init() - { - // 系统初始化逻辑 - } - - public void Destroy() - { - // 系统销毁逻辑 - } -} - -// 实现模型组件 -public class PlayerModel : IModel -{ - public void Init() - { - // 模型初始化逻辑 - } -} - -// 实现工具组件 -public class StorageUtility : IUtility -{ - // 工具类方法 -} - -// 实现命令 -public class AttackCommand : ICommand -{ - public void Execute() - { - // 命令执行逻辑 - } -} - -// 实现查询 -public class GetPlayerInfoQuery : IQuery -{ - public PlayerInfo Do() - { - // 查询执行逻辑 - } -} -``` - -### 访问框架服务 - -通过实现 [`IContextAware`](rule/IContextAware.cs) 接口,组件可以获得访问框架服务的能力: - -```csharp -public class MySystem : ISystem -{ - private IArchitectureContext _context; - - public void SetContext(IArchitectureContext context) - { - _context = context; - } - - public IArchitectureContext GetContext() - { - return _context; - } - - private void SomeMethod() - { - // 获取其他组件 - var playerModel = _context.GetModel(); - - // 发送命令 - _context.SendCommand(new AttackCommand()); - - // 发送查询 - var health = _context.SendQuery(new GetHealthQuery()); - - // 发送事件 - _context.SendEvent(new GameEvent()); - - // 注册事件监听 - _context.RegisterEvent(OnEnemySpawned); - } -} -``` - -## 相关文档 - -- [GFramework.Core](../GFramework.Core/README.md) - 核心框架实现模块 -- [GFramework.Godot](../GFramework.Godot/README.md) - Godot 平台集成模块 -- [架构模块文档](architecture/README.md) - 架构接口详细说明 -- [控制器模块文档](controller/README.md) - 控制器使用说明 - ---- - -**版本**: 1.0.0 - -**许可证**: Apache 2.0 +参见 [docs/core/](../docs/core/) 目录下的详细文档。 diff --git a/GFramework.Core.Abstractions/controller/README.md b/GFramework.Core.Abstractions/controller/README.md deleted file mode 100644 index 7ab2fa9..0000000 --- a/GFramework.Core.Abstractions/controller/README.md +++ /dev/null @@ -1,413 +0,0 @@ -# Controller 包使用说明 - -## 概述 - -Controller 包定义了控制器(Controller)的接口规范。控制器是 MVC 架构中的 C 层,负责处理用户交互、协调视图和模型,是连接表现层和业务层的桥梁。 - -**注意**:本框架使用依赖注入模式,Controller 通过构造函数或属性注入获取架构实例,而非使用全局单例。 - -## 核心接口 - -### [`IController`](IController.cs) - -控制器接口,定义了控制器需要实现的所有功能契约。 - -**继承的能力接口:** - -- [`ICanSendCommand`](../command/ICanSendCommand.cs) - 可发送命令 -- [`ICanGetSystem`](../system/ICanGetSystem.cs) - 可获取系统 -- [`ICanGetModel`](../model/ICanGetModel.cs) - 可获取模型 -- [`ICanRegisterEvent`](../events/ICanRegisterEvent.cs) - 可注册事件 -- [`ICanSendQuery`](../query/ICanSendQuery.cs) - 可发送查询 -- [`ICanGetUtility`](../utility/ICanGetUtility.cs) - 可获取工具 - -**能力说明:** - -控制器拥有框架中最全面的能力集合,可以: - -1. 发送命令执行业务逻辑 -2. 获取系统调用服务 -3. 获取模型读写数据 -4. 注册事件监听变化 -5. 发送查询获取信息 -6. 获取工具使用辅助功能 - -## 使用示例 - -### 基础控制器实现(依赖注入模式) - -```csharp -using GFramework.Core.architecture; - -// 通过依赖注入获取架构 -public class PlayerController : IController -{ - private readonly IArchitecture _architecture; - private readonly IUnRegisterList _unregisterList = new UnRegisterList(); - - // 通过构造函数注入架构 - public PlayerController(IArchitecture architecture) - { - _architecture = architecture; - } - - public void Initialize() - { - // 获取模型 - var playerModel = _architecture.GetModel(); - - // 监听模型变化 - playerModel.Health.RegisterWithInitValue(OnHealthChanged) - .AddToUnregisterList(_unregisterList); - - // 注册事件 - _architecture.RegisterEvent(OnPlayerLevelUp) - .AddToUnregisterList(_unregisterList); - } - - // 处理用户输入 - public void ProcessInput(double delta) - { - if (Input.IsActionJustPressed("attack")) - { - // 发送命令 - _architecture.SendCommand(new AttackCommand()); - } - - if (Input.IsActionJustPressed("use_item")) - { - // 发送查询 - var inventory = _architecture.SendQuery(new GetInventoryQuery()); - if (inventory.HasItem("potion")) - { - _architecture.SendCommand(new UseItemCommand("potion")); - } - } - } - - private void OnHealthChanged(int newHealth) - { - // 更新 UI 显示 - UpdateHealthBar(newHealth); - } - - private void OnPlayerLevelUp(PlayerLevelUpEvent e) - { - // 显示升级特效 - ShowLevelUpEffect(); - } - - public void Cleanup() - { - // 清理事件注册 - _unregisterList.UnRegisterAll(); - } - - private void UpdateHealthBar(int health) { /* UI 更新逻辑 */ } - private void ShowLevelUpEffect() { /* 特效逻辑 */ } -} -``` - -### UI 控制器示例 - -```csharp -// UI 面板控制器 -public class MainMenuController : IController -{ - [Inject] private IArchitecture _architecture; - [Inject] private IUISystem _uiSystem; - - [Export] private Button _startButton; - [Export] private Button _settingsButton; - [Export] private Button _quitButton; - - public void Initialize() - { - // 绑定按钮事件 - _startButton.Pressed += OnStartButtonPressed; - _settingsButton.Pressed += OnSettingsButtonPressed; - _quitButton.Pressed += OnQuitButtonPressed; - - // 获取模型更新 UI - var gameModel = _architecture.GetModel(); - UpdateUI(gameModel); - } - - private void OnStartButtonPressed() - { - // 通过命令启动游戏 - _architecture.SendCommand(); - } - - private void OnSettingsButtonPressed() - { - // 查询当前设置 - var settings = _architecture.SendQuery(new GetSettingsQuery()); - - // 打开设置面板 - _uiSystem.OpenSettingsPanel(settings); - } - - private void OnQuitButtonPressed() - { - // 发送退出命令 - _architecture.SendCommand(); - } - - private void UpdateUI(GameModel model) { /* UI 更新逻辑 */ } -} -``` - -### 复杂交互控制器 - -```csharp -// 战斗控制器 -public class CombatController : IController -{ - [Inject] protected IArchitecture _architecture; - - private IUnRegisterList _unregisterList = new UnRegisterList(); - private PlayerModel _playerModel; - private CombatSystem _combatSystem; - - [PostConstruct] - public void Init() - { - // 缓存常用引用 - _playerModel = _architecture.GetModel(); - _combatSystem = _architecture.GetSystem(); - - // 注册多个事件 - _architecture.RegisterEvent(OnEnemySpawned) - .AddToUnregisterList(_unregisterList); - - _architecture.RegisterEvent(OnCombatEnded) - .AddToUnregisterList(_unregisterList); - - // 监听模型状态 - _playerModel.CombatState.Register(OnCombatStateChanged) - .AddToUnregisterList(_unregisterList); - } - - private void OnEnemySpawned(EnemySpawnedEvent e) - { - // 进入战斗状态 - _architecture.SendCommand(new EnterCombatCommand(e.Enemy)); - } - - private void OnCombatEnded(CombatEndedEvent e) - { - if (e.Victory) - { - // 查询奖励 - var rewards = _architecture.SendQuery(new CalculateRewardsQuery(e.Enemy)); - - // 发放奖励 - _architecture.SendCommand(new GiveRewardsCommand(rewards)); - } - else - { - // 处理失败 - _architecture.SendCommand(); - } - } - - private void OnCombatStateChanged(CombatState state) - { - // 根据战斗状态更新 UI - _architecture.GetSystem().UpdateCombatUI(state); - } - - public void Cleanup() - { - _unregisterList.UnRegisterAll(); - } -} -``` - -## 控制器职责 - -### ✅ 应该做的事 - -1. **处理用户输入** - - 键盘、鼠标、触摸输入 - - UI 按钮点击 - - 手势识别 - -2. **协调视图和模型** - - 监听模型变化更新视图 - - 将用户操作转换为命令 - -3. **管理界面逻辑** - - UI 元素的显示/隐藏 - - 动画播放控制 - - 视觉反馈 - -4. **事件监听** - - 注册关心的事件 - - 响应事件更新界面 - -### ❌ 不应该做的事 - -1. **不包含业务逻辑** - - 业务逻辑应该在 System 中 - - 控制器只负责调用和协调 - -2. **不直接修改模型** - - 应该通过 Command 修改模型 - - 避免直接访问 Model 的 setter - -3. **不处理复杂计算** - - 复杂计算应该在 Query 或 System 中 - - 控制器保持简洁 - -4. **不保存核心状态** - - 核心状态应该在 Model 中 - - 控制器可以保存临时 UI 状态 - -## 生命周期管理 - -### 事件注销 - -```csharp -public class MyController : IController -{ - [Inject] private IArchitecture _architecture; - - // 使用 UnRegisterList 统一管理 - private IUnRegisterList _unregisterList = new UnRegisterList(); - - public void Initialize() - { - // 所有事件注册都添加到列表 - _architecture.RegisterEvent(OnGameEvent) - .AddToUnregisterList(_unregisterList); - - _architecture.GetModel().Health.Register(OnHealthChanged) - .AddToUnregisterList(_unregisterList); - } - - public void Cleanup() - { - // 统一注销所有事件 - _unregisterList.UnRegisterAll(); - } -} -``` - -## 最佳实践 - -1. **使用依赖注入获取依赖** - - 通过构造函数注入 `IArchitecture` - - 使用 `[Inject]` 属性标记注入字段 - -2. **保持控制器轻量** - - 复杂逻辑放在 Command、Query、System 中 - - 控制器只做协调和转发 - -3. **合理使用缓存** - - 频繁使用的 Model、System 可以缓存引用 - - 平衡性能和内存占用 - -4. **统一管理事件注销** - - 使用 `IUnRegisterList` 统一管理 - - 在 `Cleanup()` 中统一注销 - -5. **命名规范** - - 控制器类名:`XxxController` - - 使用 `[Inject]` 或构造函数注入获取架构 - -## 常见模式 - -### 数据绑定模式 - -```csharp -public class ScoreController : IController -{ - [Inject] private IArchitecture _architecture; - - public void Initialize() - { - // 绑定模型数据到 UI - _architecture.GetModel() - .Score - .RegisterWithInitValue(score => UpdateDisplay(score)) - .AddToUnregisterList(_unregisterList); - } - - private void UpdateDisplay(int score) - { - // 更新分数显示 - } -} -``` - -### 状态机模式 - -```csharp -public class PlayerStateController : IController -{ - [Inject] private IArchitecture _architecture; - private Dictionary _stateHandlers; - - public void Initialize() - { - _stateHandlers = new Dictionary - { - { PlayerState.Idle, HandleIdleState }, - { PlayerState.Moving, HandleMovingState }, - { PlayerState.Attacking, HandleAttackingState } - }; - - _architecture.GetModel() - .State - .Register(OnStateChanged) - .AddToUnregisterList(_unregisterList); - } - - private void OnStateChanged(PlayerState state) - { - _stateHandlers[state]?.Invoke(); - } -} -``` - -## 与 Godot 集成 - -在 Godot 项目中,可以使用 GFramework.Godot 提供的扩展: - -```csharp -using GFramework.Godot; - -public partial class GodotPlayerController : Node, IController -{ - [Inject] private IArchitecture _architecture; - - public override void _Ready() - { - // 使用 Godot 特定的自动注销扩展 - _architecture.RegisterEvent(OnPlayerDied) - .UnRegisterWhenNodeExitTree(this); - - _architecture.GetModel() - .Health - .RegisterWithInitValue(OnHealthChanged) - .UnRegisterWhenNodeExitTree(this); - } -} -``` - -## 相关包 - -- [`architecture`](../architecture/README.md) - 提供架构访问能力 -- [`command`](../command/README.md) - 控制器发送命令执行业务逻辑 -- [`query`](../query/README.md) - 控制器发送查询获取数据 -- [`events`](../events/README.md) - 控制器注册事件监听变化 -- [`model`](../model/README.md) - 控制器读取模型数据 -- [`system`](../system/README.md) - 控制器调用系统服务 -- [`extensions`](../extensions/README.md) - 提供便捷的扩展方法 -- **GFramework.Godot** - Godot 特定的控制器扩展 - ---- - -**许可证**: Apache 2.0 diff --git a/GFramework.Core/README.md b/GFramework.Core/README.md new file mode 100644 index 0000000..c4fb096 --- /dev/null +++ b/GFramework.Core/README.md @@ -0,0 +1,31 @@ +# GFramework.Core + +GFramework 框架的核心模块,提供MVC架构的基础设施。 + +## 主要功能 + +- **Architecture** - 应用程序架构管理,支持依赖注入、生命周期管理和模块化扩展 +- **Model** - 数据模型层,管理应用状态和数据 +- **System** - 业务逻辑层,处理核心业务逻辑和事件响应 +- **Controller** - 控制器层,处理用户输入和UI协调 +- **Command** - 命令模式实现,封装用户操作 +- **Query** - 查询模式实现,支持CQRS架构 +- **Events** - 事件系统,实现组件间松耦合通信 +- **IoC** - 轻量级依赖注入容器 +- **Property** - 可绑定属性,支持数据绑定和响应式编程 +- **Utility** - 无状态工具类 +- **Pool** - 对象池系统,减少GC压力 +- **Extensions** - 框架扩展方法 +- **Logging** - 日志系统 +- **Environment** - 环境配置管理 + +## 设计原则 + +- 与平台解耦,不依赖特定游戏引擎 +- 接口隔离,职责单一 +- 依赖倒置,面向接口编程 +- 组合优于继承 + +## 详细文档 + +参见 [docs/core/](../docs/core/) 目录下的详细文档。 diff --git a/GFramework.Core/architecture/README.md b/GFramework.Core/architecture/README.md deleted file mode 100644 index 7c0550e..0000000 --- a/GFramework.Core/architecture/README.md +++ /dev/null @@ -1,509 +0,0 @@ -# Architecture 包使用说明 - -## 概述 - -Architecture 包是整个框架的核心,提供了基于 MVC 架构模式的应用程序架构基础。它实现了依赖注入(IoC)容器、组件生命周期管理,以及命令、查询、事件的统一调度机制。 - -**注意**:本框架的 Core 模块与 Godot 解耦,Godot 相关集成在 GFramework.Godot 包中实现。 - -## 核心接口 - -### IArchitecture - -架构接口,定义了框架的核心功能契约。 - -**主要职责:** - -- 组件注册:注册 System、Model、Utility -- 组件获取:从容器中获取已注册的组件 -- 命令处理:发送并执行命令 -- 查询处理:发送并执行查询 -- 事件管理:发送、注册、注销事件 - -**核心方法:** - -```csharp -// 组件注册 -void RegisterSystem(TSystem system) where TSystem : ISystem; -void RegisterModel(TModel model) where TModel : IModel; -void RegisterUtility(TUtility utility) where TUtility : IUtility; - -// 组件获取(通过容器) -T GetModel() where T : class, IModel; -T GetSystem() where T : class, ISystem; -T GetUtility() where T : class, IUtility; - -// 命令处理 -void SendCommand(ICommand command); -TResult SendCommand(ICommand command); - -// 查询处理 -TResult SendQuery(IQuery query); - -// 事件管理 -void SendEvent() where T : new(); -void SendEvent(T e); -IUnRegister RegisterEvent(Action onEvent); -void UnRegisterEvent(Action onEvent); -``` - -### IArchitecturePhaseAware - -架构阶段感知接口,允许组件监听架构阶段变化。 - -**核心方法:** - -```csharp -void OnArchitecturePhase(ArchitecturePhase phase); -``` - -### IArchitectureModule - -架构模块接口,支持模块化架构扩展。 - -**核心方法:** - -```csharp -void Install(IArchitecture architecture); -``` - -### IAsyncInitializable - -异步初始化接口,支持组件异步初始化。 - -**核心方法:** - -```csharp -Task InitializeAsync(); -``` - -## 核心类 - -### [`Architecture`](Architecture.cs) - -架构基类,实现了 `IArchitecture` 接口,提供完整的架构功能实现。 - -**构造函数参数:** - -```csharp -public abstract class Architecture( - IArchitectureConfiguration? configuration = null, - IEnvironment? environment = null, - IArchitectureServices? services = null, - IArchitectureContext? context = null -) -``` - -**特性:** - -- **阶段式生命周期管理** - :支持多个架构阶段(BeforeUtilityInit、AfterUtilityInit、BeforeModelInit、AfterModelInit、BeforeSystemInit、AfterSystemInit、Ready、Destroying、Destroyed) -- **模块安装系统**:支持通过 `InstallModule` 扩展架构功能 -- **异步初始化**:支持同步和异步两种初始化方式 -- **IoC 容器集成**:内置依赖注入容器 -- **事件系统集成**:集成类型化事件系统 -- **与平台无关**:Core 模块不依赖 Godot,可以在任何 .NET 环境中使用 - -**架构阶段:** - -```csharp -public enum ArchitecturePhase -{ - None = 0, // 初始阶段 - BeforeUtilityInit = 1, // 工具初始化前 - AfterUtilityInit = 2, // 工具初始化后 - BeforeModelInit = 3, // 模型初始化前 - AfterModelInit = 4, // 模型初始化后 - BeforeSystemInit = 5, // 系统初始化前 - AfterSystemInit = 6, // 系统初始化后 - Ready = 7, // 就绪状态 - FailedInitialization = 8, // 初始化失败 - Destroying = 9, // 正在销毁 - Destroyed = 10 // 已销毁 -} -``` - -**初始化流程:** - -1. 创建架构实例(传入配置或使用默认配置) -2. 调用用户自定义的 `Init()` 方法 -3. 初始化上下文工具(Context Utility) -4. 初始化所有注册的 Model -5. 初始化所有注册的 System -6. 冻结 IOC 容器 -7. 进入 Ready 阶段 - -**销毁流程:** - -1. 进入 Destroying 阶段 -2. 发送 `ArchitectureDestroyingEvent` 事件 -3. 销毁所有 System -4. 进入 Destroyed 阶段 -5. 发送 `ArchitectureDestroyedEvent` 事件 - -**使用示例:** - -``csharp -// 1. 定义你的架构(继承 Architecture 基类) -public class GameArchitecture : Architecture -{ -protected override void Init() -{ -// 注册 Model -RegisterModel(new PlayerModel()); -RegisterModel(new InventoryModel()); - - // 注册 System - RegisterSystem(new GameplaySystem()); - RegisterSystem(new SaveSystem()); - - // 注册 Utility - RegisterUtility(new StorageUtility()); - RegisterUtility(new TimeUtility()); - } - -} - -// 2. 创建并初始化架构 -var architecture = new GameArchitecture(); -architecture.Initialize(); - -// 或者异步初始化 -// var architecture = new GameArchitecture(); -// await architecture.InitializeAsync(); - -// 3. 通过依赖注入使用架构 -// 在 Controller 或其他组件中注入架构实例 -public class GameController : IController -{ -private readonly IArchitecture _architecture; - - // 通过构造函数注入架构 - public GameController(IArchitecture architecture) - { - _architecture = architecture; - } - - public void Start() - { - // 获取 Model - var playerModel = _architecture.GetModel(); - - // 发送命令 - _architecture.SendCommand(new StartGameCommand()); - - // 发送查询 - var score = _architecture.SendQuery(new GetScoreQuery()); - - // 注册事件 - _architecture.RegisterEvent(OnPlayerDied); - } - - private void OnPlayerDied(PlayerDiedEvent e) - { - // 处理玩家死亡事件 - } - -} - -``` - -**核心方法与属性:** - -### 初始化方法 - -#### `Initialize()` - -同步初始化方法,阻塞当前线程直到初始化完成。 - -```csharp -public void Initialize() -``` - -**使用示例:** - -```csharp -var architecture = new GameArchitecture(); -architecture.Initialize(); // 阻塞等待初始化完成 -``` - -**异常处理:** - -如果初始化过程中发生异常,架构会进入 `FailedInitialization` 阶段并发送 `ArchitectureFailedInitializationEvent` 事件。 - -#### `InitializeAsync()` - -异步初始化方法,返回 Task 以便调用者可以等待初始化完成。 - -```csharp -public async Task InitializeAsync() -``` - -**使用示例:** - -```csharp -var architecture = new GameArchitecture(); -await architecture.InitializeAsync(); // 异步等待初始化完成 -``` - -**优势:** - -- 支持异步初始化 Model 和 System -- 可以利用异步 I/O 操作(如异步加载数据) -- 提高初始化性能 - -### 模块管理 - -#### `InstallModule(IArchitectureModule module)` - -安装架构模块,用于扩展架构功能。 - -```csharp -public void InstallModule(IArchitectureModule module) -``` - -**参数:** - -- `module`:要安装的模块实例 - -**使用示例:** - -```csharp -// 定义模块 -public class NetworkModule : IArchitectureModule -{ - public void Install(IArchitecture architecture) - { - // 注册网络相关的 System 和 Utility - architecture.RegisterSystem(new NetworkSystem()); - architecture.RegisterUtility(new HttpClientUtility()); - } -} - -// 安装模块 -var architecture = new GameArchitecture(); -architecture.InstallModule(new NetworkModule()); -``` - -### 生命周期钩子 - -#### `RegisterLifecycleHook(IArchitectureLifecycle hook)` - -注册生命周期钩子,用于在架构阶段变化时执行自定义逻辑。 - -```csharp -public void RegisterLifecycleHook(IArchitectureLifecycle hook) -``` - -**参数:** - -- `hook`:生命周期钩子实例 - -**使用示例:** - -```csharp -// 定义生命周期钩子 -public class PerformanceMonitorHook : IArchitectureLifecycle -{ - public void OnPhase(ArchitecturePhase phase, IArchitecture architecture) - { - switch (phase) - { - case ArchitecturePhase.BeforeModelInit: - Console.WriteLine("开始监控 Model 初始化性能"); - break; - case ArchitecturePhase.AfterModelInit: - Console.WriteLine("Model 初始化完成,停止监控"); - break; - case ArchitecturePhase.Ready: - Console.WriteLine("架构就绪,开始性能统计"); - break; - } - } -} - -// 注册生命周期钩子 -var architecture = new GameArchitecture(); -architecture.RegisterLifecycleHook(new PerformanceMonitorHook()); -architecture.Initialize(); -``` - -**注意:** 生命周期钩子只能在架构进入 Ready 阶段之前注册。 - -### 属性 - -#### `CurrentPhase` - -获取当前架构的阶段。 - -```csharp -public ArchitecturePhase CurrentPhase { get; } -``` - -**使用示例:** - -```csharp -var architecture = new GameArchitecture(); - -// 检查架构是否已就绪 -if (architecture.CurrentPhase == ArchitecturePhase.Ready) -{ - Console.WriteLine("架构已就绪,可以开始游戏"); -} - -// 在异步操作中检查阶段变化 -await Task.Run(async () => -{ - while (architecture.CurrentPhase != ArchitecturePhase.Ready) - { - Console.WriteLine($"当前阶段: {architecture.CurrentPhase}"); - await Task.Delay(100); - } -}); -``` - -#### `Context` - -获取架构上下文,提供对架构服务的访问。 - -```csharp -public IArchitectureContext Context { get; } -``` - -**使用示例:** - -```csharp -// 通过 Context 访问服务 -var context = architecture.Context; -var eventBus = context.EventBus; -var commandBus = context.CommandBus; -var queryBus = context.QueryBus; -var environment = context.Environment; -``` - -**高级特性:** - -``csharp -// 1. 使用自定义配置 -var config = new ArchitectureConfiguration(); -var architecture = new GameArchitecture(configuration: config); - -// 2. 模块安装 -var module = new GameModule(); -architecture.InstallModule(module); - -// 3. 监听架构阶段变化 -public class GamePhaseListener : IArchitecturePhaseAware -{ -public void OnArchitecturePhase(ArchitecturePhase phase) -{ -switch (phase) -{ -case ArchitecturePhase.Ready: -GD.Print("架构已就绪,可以开始游戏了"); -break; -case ArchitecturePhase.Destroying: -GD.Print("架构正在销毁"); -break; -} -} -} - -// 4. 生命周期钩子 -public class LifecycleHook : IArchitectureLifecycle -{ -public void OnPhase(ArchitecturePhase phase, IArchitecture architecture) -{ -GD.Print($"架构阶段变化: {phase}"); -} -} - -``` - -### [`ArchitectureConfiguration`](ArchitectureConfiguration.cs) - -架构配置类,用于配置架构的行为。 - -**使用示例:** - -``csharp -var config = new ArchitectureConfiguration -{ - // 严格阶段验证 - StrictPhaseValidation = true, - // 允许延迟注册 - AllowLateRegistration = false -}; - -var architecture = new GameArchitecture(configuration: config); -``` - -### [`ArchitectureServices`](ArchitectureServices.cs) - -架构服务类,管理命令总线、查询总线、IOC容器和类型事件系统。 - -### [`ArchitectureContext`](ArchitectureContext.cs) - -架构上下文类,提供对架构服务的访问。 - -### [`GameContext`](GameContext.cs) - -游戏上下文类,管理架构上下文与类型的绑定关系。 - -## 设计模式 - -### 1. 依赖注入 - -通过构造函数注入或容器解析获取架构实例。 - -### 2. 依赖注入(IoC) - -使用内置 IoC 容器管理组件生命周期和依赖关系。 - -### 3. 命令模式 - -通过 `ICommand` 封装所有用户操作。 - -### 4. 查询模式(CQRS) - -通过 `IQuery` 分离查询和命令操作。 - -### 5. 观察者模式 - -通过事件系统实现组件间的松耦合通信。 - -### 6. 阶段式生命周期管理 - -通过 `ArchitecturePhase` 枚举和生命周期钩子管理架构状态。 - -### 7. 组合优于继承 - -通过接口组合获得不同能力,而不是深层继承链。 - -## 最佳实践 - -1. **保持架构类简洁**:只在 `Init()` 中注册组件,不要包含业务逻辑 -2. **合理划分职责**: - - Model:数据和状态 - - System:业务逻辑和规则 - - Utility:无状态的工具方法 -3. **使用依赖注入**:通过构造函数注入架构实例,便于测试 -4. **事件命名规范**:使用过去式命名事件类,如 `PlayerDiedEvent` -5. **避免循环依赖**:System 不应直接引用 System,应通过事件通信 -6. **使用模块扩展**:通过 `IArchitectureModule` 实现架构的可扩展性 -7. **Core 模块与平台解耦**:GFramework.Core 不包含 Godot 相关代码,Godot 集成在单独模块中 - -## 相关包 - -- [`command`](../command/README.md) - 命令模式实现 -- [`query`](../query/README.md) - 查询模式实现 -- [`events`](../events/README.md) - 事件系统 -- [`ioc`](../ioc/README.md) - IoC 容器 -- [`model`](../model/README.md) - 数据模型 -- [`system`](../system/README.md) - 业务系统 -- [`utility`](../utility/README.md) - 工具类 -- **GFramework.Godot** - Godot 特定集成(GodotNode 扩展、GodotLogger 等) - ---- - -**许可证**: Apache 2.0 diff --git a/GFramework.Core/command/README.md b/GFramework.Core/command/README.md deleted file mode 100644 index a84e49a..0000000 --- a/GFramework.Core/command/README.md +++ /dev/null @@ -1,309 +0,0 @@ -# Command 包使用说明 - -## 概述 - -Command 包实现了命令模式(Command Pattern),用于封装用户操作和业务逻辑。通过命令模式,可以将请求封装为对象,实现操作的参数化、队列化、日志记录、撤销等功能。 - -## 核心接口 - -### 1. [`ICommand`](ICommand.cs) - -无返回值命令接口,定义了命令的基本契约。 - -**核心方法:** - -```csharp -void Execute(); // 执行命令 -``` - -### 2. [`ICommand`](ICommand.cs) - -带返回值的命令接口,用于需要返回执行结果的命令。 - -**核心方法:** - -```csharp -TResult Execute(); // 执行命令并返回结果 -``` - -## 核心类 - -### 1. [`AbstractCommand`](AbstractCommand.cs) - -无返回值命令的抽象基类,提供了命令的基础实现。它继承自 [ContextAwareBase](file:///d:/Project/Rider/GFramework/GFramework.Core.Abstractions/rule/IContextAware.cs#L4-L28) -,具有上下文感知能力。 - -**使用示例:** - -```csharp -// 定义一个命令输入参数 -public struct StartGameCommandInput : ICommandInput -{ - public int LevelId { get; set; } - public string PlayerName { get; set; } -} - -// 定义一个开始游戏的命令 -public class StartGameCommand : AbstractCommand -{ - public StartGameCommand(StartGameCommandInput input) : base(input) - { - } - - protected override void OnExecute(StartGameCommandInput input) - { - // 获取需要的模型 - var playerModel = this.GetModel(); - var gameModel = this.GetModel(); - - // 执行业务逻辑 - playerModel.PlayerName.Value = input.PlayerName; - gameModel.CurrentLevel.Value = input.LevelId; - gameModel.GameState.Value = GameState.Playing; - - // 发送事件通知其他模块 - this.SendEvent(new GameStartedEvent()); - } -} - -// 使用命令 -public class GameController : IController -{ - public IArchitecture GetArchitecture() => GameArchitecture.Interface; - - public void OnStartButtonClicked() - { - // 发送命令实例 - this.SendCommand(new StartGameCommand(new StartGameCommandInput - { - LevelId = 1, - PlayerName = "Player1" - })); - } -} -``` - -### 2. [`AbstractCommand`](AbstractCommand.cs) - -带返回值命令的抽象基类,同样继承自 [ContextAwareBase](file:///d:/Project/Rider/GFramework/GFramework.Core.Abstractions/rule/IContextAware.cs#L4-L28)。 - -**使用示例:** - -```csharp -// 定义一个计算伤害的命令输入 -public struct CalculateDamageCommandInput : ICommandInput -{ - public int AttackerAttackPower { get; set; } - public int DefenderDefense { get; set; } -} - -// 定义一个计算伤害的命令 -public class CalculateDamageCommand : AbstractCommand -{ - public CalculateDamageCommand(CalculateDamageCommandInput input) : base(input) - { - } - - protected override int OnExecute(CalculateDamageCommandInput input) - { - // 获取游戏配置 - var config = this.GetModel(); - - // 计算最终伤害 - var baseDamage = input.AttackerAttackPower - input.DefenderDefense; - var finalDamage = Math.Max(1, baseDamage * config.DamageMultiplier); - - return (int)finalDamage; - } -} - -// 使用带返回值的命令 -public class CombatSystem : AbstractSystem -{ - protected override void OnInit() { } - - public void Attack(Character attacker, Character defender) - { - // 发送命令并获取返回值 - var damage = this.SendCommand(new CalculateDamageCommand(new CalculateDamageCommandInput - { - AttackerAttackPower = attacker.AttackPower, - DefenderDefense = defender.Defense - })); - - // 应用伤害 - defender.Health -= damage; - - // 发送伤害事件 - this.SendEvent(new DamageDealtEvent(attacker, defender, damage)); - } -} -``` - -## 命令的生命周期 - -1. **创建命令**:实例化命令对象,传入必要的参数 -2. **执行命令**:调用 `Execute()` 方法,内部委托给 `OnExecute()` -3. **返回结果**:对于带返回值的命令,返回执行结果 -4. **命令销毁**:命令执行完毕后可以被垃圾回收 - -## CommandBus - 命令总线 - -### 功能说明 - -[CommandBus](file:///d:/Project/Rider/GFramework/GFramework.Core/command/CommandBus.cs#L8-L34) 是命令执行的核心组件,负责发送和执行命令。 - -**主要方法:** - -```csharp -void Send(ICommand command); // 发送无返回值命令 -TResult Send(ICommand command); // 发送带返回值命令 -``` - -### 使用示例 - -```csharp -var commandBus = new CommandBus(); - -// 发送无返回值命令 -commandBus.Send(new StartGameCommand(new StartGameCommandInput())); - -// 发送带返回值命令 -var result = commandBus.Send(new CalculateDamageCommand(new CalculateDamageCommandInput())); -``` - -## EmptyCommandInput - 空命令输入 - -当命令不需要输入参数时,可以使用 `EmptyCommandInput` 类: - -```csharp -public class SimpleActionCommand : AbstractCommand -{ - public SimpleActionCommand(EmptyCommandInput input) : base(input) - { - } - - protected override void OnExecute(EmptyCommandInput input) - { - // 执行简单操作,无需额外参数 - this.SendEvent(new SimpleActionEvent()); - } -} -``` - -## 使用场景 - -### 1. 用户交互操作 - -```csharp -public struct SaveGameCommandInput : ICommandInput -{ - public string SaveSlot { get; set; } -} - -public class SaveGameCommand : AbstractCommand -{ - public SaveGameCommand(SaveGameCommandInput input) : base(input) - { - } - - protected override void OnExecute(SaveGameCommandInput input) - { - var saveSystem = this.GetSystem(); - var playerModel = this.GetModel(); - - saveSystem.SavePlayerData(playerModel, input.SaveSlot); - this.SendEvent(new GameSavedEvent(input.SaveSlot)); - } -} -``` - -### 2. 业务流程控制 - -```csharp -public struct LoadLevelCommandInput : ICommandInput -{ - public int LevelId { get; set; } -} - -public class LoadLevelCommand : AbstractCommand -{ - public LoadLevelCommand(LoadLevelCommandInput input) : base(input) - { - } - - protected override void OnExecute(LoadLevelCommandInput input) - { - var levelSystem = this.GetSystem(); - var uiSystem = this.GetSystem(); - - // 显示加载界面 - uiSystem.ShowLoadingScreen(); - - // 加载关卡 - levelSystem.LoadLevel(input.LevelId); - - // 发送事件 - this.SendEvent(new LevelLoadedEvent(input.LevelId)); - } -} -``` - -## 最佳实践 - -1. **保持命令原子性**:一个命令应该完成一个完整的业务操作 -2. **命令无状态**:命令不应该保存长期状态,执行完即可丢弃 -3. **参数通过构造函数传递**:命令需要的参数应在创建时传入 -4. **避免命令嵌套**:命令内部尽量不要发送其他命令,使用事件通信 -5. **合理使用返回值**:只在确实需要返回结果时使用 `AbstractCommand` -6. **命令命名规范**:使用动词+名词形式,如 `StartGameCommand`、`SavePlayerCommand` -7. **输入参数结构化**:使用 `ICommandInput` 接口的实现类来组织命令参数 - -## 扩展功能 - -### 命令撤销/重做(可扩展) - -```csharp -public struct MoveCommandInput : ICommandInput -{ - public Vector3 NewPosition { get; set; } -} - -// 实现可撤销命令 -public class MoveCommand : AbstractCommand, 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(); - _oldPosition = player.Position; - player.Position = input.NewPosition; - } - - public void Undo() - { - var player = this.GetModel(); - player.Position = _oldPosition; - } -} -``` - -## 相关包 - -- [`architecture`](../architecture/README.md) - 架构核心,负责命令的分发和执行 -- [`extensions`](../extensions/README.md) - 提供 `SendCommand()` 扩展方法 -- [`query`](../query/README.md) - 查询模式,用于数据查询 -- [`events`](../events/README.md) - 事件系统,命令执行后的通知机制 -- [`system`](../system/README.md) - 业务系统,命令的主要执行者 -- [`model`](../model/README.md) - 数据模型,命令操作的数据 - ---- - -**许可证**: Apache 2.0 \ No newline at end of file diff --git a/GFramework.Core/environment/README.md b/GFramework.Core/environment/README.md deleted file mode 100644 index 2db0ef1..0000000 --- a/GFramework.Core/environment/README.md +++ /dev/null @@ -1,218 +0,0 @@ -# Environment 包使用说明 - -## 概述 - -Environment 包定义了环境配置功能。Environment 提供了一个键值对存储系统,用于在运行时存储和获取各种环境特定的值,如配置选项、路径设置等。它允许应用程序在不同环境下灵活调整行为。 - -## 核心接口 - -### IEnvironment - -环境接口,定义了环境值的存储和获取功能。 - -**核心成员:** - -```csharp -string Name { get; } // 环境名称 -T? Get(string key) where T : class; // 根据键获取值 -bool TryGet(string key, out T value) where T : class; // 尝试获取值 -T GetRequired(string key) where T : class; // 获取必需值(不存在则抛异常) -void Register(string key, object value); // 注册键值对 -void Initialize(); // 初始化环境 -``` - -## 核心类 - -### [`EnvironmentBase`](EnvironmentBase.cs) - -环境基础抽象类,实现了 IEnvironment 接口,提供环境值的存储和获取功能。 - -**使用方式:** - -```csharp -public abstract class EnvironmentBase : ContextAwareBase, IEnvironment -{ - protected readonly Dictionary Values = new(); // 存储环境值 - - public abstract string Name { get; } // 环境名称 - - public virtual T? Get(string key) where T : class - { - return TryGet(key, out var value) ? value : null; - } - - public virtual bool TryGet(string key, out T value) where T : class - { - if (Values.TryGetValue(key, out var obj) && obj is T typed) - { - value = typed; - return true; - } - - value = null!; - return false; - } - - public virtual T GetRequired(string key) where T : class - { - if (TryGet(key, out var value)) - return value; - - throw new InvalidOperationException( - $"Environment [{Name}] missing required value: key='{key}', type='{typeof(T).Name}'"); - } - - void IEnvironment.Register(string key, object value); - protected void Register(string key, object value); // 注册键值对 - public abstract void Initialize(); // 初始化环境 -} -``` - -### [`DefaultEnvironment`](DefaultEnvironment.cs) - -默认环境实现类,继承自 EnvironmentBase。 - -**使用方式:** - -```csharp -public class DefaultEnvironment : EnvironmentBase -{ - public override string Name { get; } = "Default"; // 环境名称 - - public override void Initialize() - { - // 默认环境初始化逻辑 - } -} -``` - -## 基本使用 - -### 1. 定义自定义环境 - -```csharp -public class GameEnvironment : EnvironmentBase -{ - public override string Name { get; } = "Game"; - - public override void Initialize() - { - // 注册一些环境特定的值 - Register("GameMode", "Survival"); - Register("MaxPlayers", 4); - Register("ServerAddress", "localhost"); - } - - // 便捷方法 - public string GameMode => Get("GameMode") ?? "Default"; - public int MaxPlayers => Get("MaxPlayers") ?? 1; - public string ServerAddress => Get("ServerAddress") ?? "localhost"; -} -``` - -### 2. 在架构中使用环境 - -```csharp -public class GameArchitecture : Architecture -{ - protected override void Init() - { - // 环境已经在架构初始化过程中自动初始化 - // 但是我们可以在需要的时候获取环境值 - var gameMode = this.Context.Environment.Get("GameMode"); - - // 注册模型和系统 - RegisterModel(new PlayerModel()); - RegisterSystem(new GameplaySystem()); - } -} -``` - -### 3. 使用环境值 - -```csharp -public class NetworkSystem : AbstractSystem -{ - private string _serverAddress; - - protected override void OnInit() - { - // 从环境中获取服务器地址 - _serverAddress = this.GetContext().Environment.Get("ServerAddress") ?? "localhost"; - - // 注册事件 - this.RegisterEvent(OnConnectToServer); - } - - private void OnConnectToServer(ConnectToServerEvent e) - { - // 使用环境中的服务器地址 - Connect(_serverAddress, e.Port); - } - - private void Connect(string address, int port) - { - // 连接逻辑 - } -} -``` - -## Environment vs Configuration - -### Environment(环境) - -- **动态性**:运行时可以更改 -- **灵活性**:根据部署环境调整行为 -- **存储类型**:运行时值、连接信息等 -- **访问方式**:通过键值对访问 - -### Configuration(配置) - -- **静态性**:通常在启动时确定 -- **持久性**:保存在文件或外部源 -- **存储类型**:应用设置、参数等 -- **访问方式**:通过配置对象访问 - -## 最佳实践 - -1. **明确环境名称**:为每个环境提供有意义的名称 -2. **类型安全**:使用泛型方法确保类型安全 -3. **错误处理**:使用 GetRequired 方法获取必需值 -4. **初始化时机**:在架构初始化期间完成环境设置 -5. **避免过度使用**:仅存储环境相关的值 - -## 错误示例 - -```csharp -// ❌ 错误:获取必需值但不存在 -public class BadExampleSystem : AbstractSystem -{ - protected override void OnInit() - { - // 如果"RequiredValue"不存在,这会抛出异常 - var value = this.GetContext().Environment.GetRequired("RequiredValue"); - } -} - -// ✅ 正确:安全获取值 -public class GoodExampleSystem : AbstractSystem -{ - protected override void OnInit() - { - // 使用 TryGet 安全获取值 - if (this.GetContext().Environment.TryGet("OptionalValue", out var value)) - { - // 处理值 - } - - // 或者提供默认值 - var gameMode = this.GetContext().Environment.Get("GameMode") ?? "Default"; - } -} -``` - -## 相关包 - -- [`architecture`](../architecture/README.md) - 在架构中使用环境配置 -- [`rule`](../rule/README.md) - 环境基类继承自 ContextAwareBase -- [`ioc`](../ioc/README.md) - 环境值可通过IoC容器管理 \ No newline at end of file diff --git a/GFramework.Core/events/README.md b/GFramework.Core/events/README.md deleted file mode 100644 index 26e9207..0000000 --- a/GFramework.Core/events/README.md +++ /dev/null @@ -1,524 +0,0 @@ -# Events 包使用说明 - -## 概述 - -Events 包提供了一套完整的事件系统,实现了观察者模式(Observer Pattern)。通过事件系统,可以实现组件间的松耦合通信,支持无参和带参事件、事件注册/注销、以及灵活的事件组合。 - -## 核心接口 - -### 1. [`IEvent`](file:///d:/Project/Rider/GFramework/GFramework.Core.Abstractions/events/IEvent.cs#L7-L11) - -基础事件接口,定义了事件注册的基本功能。 - -**核心方法:** - -```csharp -IUnRegister Register(Action onEvent); // 注册事件处理函数 -``` - -### 2. [`IUnRegister`](file:///d:/Project/Rider/GFramework/GFramework.Core.Abstractions/events/IUnRegister.cs#L6-L10) - -注销接口,用于取消事件注册。 - -**核心方法:** - -```csharp -void UnRegister(); // 执行注销操作 -``` - -### 3. [ - -`IUnRegisterList`](file:///d:/Project/Rider/GFramework/GFramework.Core.Abstractions/events/IUnRegisterList.cs#L6-L10) - -注销列表接口,用于批量管理注销对象。 - -**属性:** - -```csharp -IList UnregisterList { get; } // 获取注销列表 -``` - -### 4. [`IEventBus`](file:///d:/Project/Rider/GFramework/GFramework.Core.Abstractions/events/IEventBus.cs#L6-L22) - -事件总线接口,提供基于类型的事件发送和注册。 - -**核心方法:** - -```csharp -IUnRegister Register(Action onEvent); // 注册类型化事件 -void Send(T e); // 发送事件实例 -void Send() where T : new(); // 发送事件(自动创建实例) -``` - -## 核心类 - -### 1. [`EasyEvent`](EasyEvent.cs) - -无参事件类,支持注册、注销和触发无参事件。 - -**使用示例:** - -```csharp -// 创建事件 -var onClicked = new EasyEvent(); - -// 注册监听 -var unregister = onClicked.Register(() => -{ - GD.Print("Button clicked!"); -}); - -// 触发事件 -onClicked.Trigger(); - -// 取消注册 -unregister.UnRegister(); -``` - -### 2. [`Event`](EasyEventGeneric.cs) - -单参数泛型事件类,支持一个参数的事件。 - -**使用示例:** - -```csharp -// 创建带参数的事件 -var onScoreChanged = new Event(); - -// 注册监听 -onScoreChanged.Register(newScore => -{ - GD.Print($"Score changed to: {newScore}"); -}); - -// 触发事件并传递参数 -onScoreChanged.Trigger(100); -``` - -### 3. [`Event`](EasyEventGeneric.cs) - -双参数泛型事件类。 - -**使用示例:** - -```csharp -// 伤害事件:攻击者、伤害值 -var onDamageDealt = new Event(); - -onDamageDealt.Register((attacker, damage) => -{ - GD.Print($"{attacker} dealt {damage} damage!"); -}); - -onDamageDealt.Trigger("Player", 50); -``` - -### 4. [`EasyEvents`](EasyEvents.cs) - -全局事件管理器,提供类型安全的事件注册和获取。 - -**使用示例:** - -```csharp -// 注册全局事件类型 -EasyEvents.Register(); - -// 获取事件实例 -var gameStartEvent = EasyEvents.Get(); - -// 注册监听 -gameStartEvent.Register(() => -{ - GD.Print("Game started!"); -}); - -// 触发事件 -gameStartEvent.Trigger(); -``` - -### 5. [`EventBus`](EventBus.cs) - -类型化事件系统,支持基于类型的事件发送和注册。 - -**使用示例:** - -```csharp -// 使用全局事件系统 -var eventBus = new EventBus(); - -// 注册类型化事件 -eventBus.Register(e => -{ - GD.Print($"Player died at position: {e.Position}"); -}); - -// 发送事件(传递实例) -eventBus.Send(new PlayerDiedEvent -{ - Position = new Vector3(10, 0, 5) -}); - -// 发送事件(自动创建实例) -eventBus.Send(); -``` - -### 6. [`DefaultUnRegister`](DefaultUnRegister.cs) - -默认注销器实现,封装注销回调。 - -**使用示例:** - -```csharp -Action onUnregister = () => GD.Print("Unregistered"); -var unregister = new DefaultUnRegister(onUnregister); - -// 执行注销 -unregister.UnRegister(); -``` - -### 7. [`OrEvent`](OrEvent.cs) - -事件或运算组合器,当任意一个事件触发时触发。 - -**使用示例:** - -```csharp -var onAnyInput = new OrEvent() - .Or(onKeyPressed) - .Or(onMouseClicked) - .Or(onTouchDetected); - -// 当上述任意事件触发时,执行回调 -onAnyInput.Register(() => -{ - GD.Print("Input detected!"); -}); -``` - -### 8. [`UnRegisterList`](UnRegisterList.cs) - -批量管理注销对象的列表。 - -**使用示例:** - -```csharp -var unregisterList = new UnRegisterList(); - -// 添加到列表 -someEvent.Register(OnEvent).AddToUnregisterList(unregisterList); - -// 批量注销 -unregisterList.UnRegisterAll(); -``` - -### 9. [`ArchitectureEvents`](ArchitectureEvents.cs) - -定义了架构生命周期相关的事件。 - -**包含事件:** - -- `ArchitectureLifecycleReadyEvent` - 架构生命周期准备就绪 -- `ArchitectureDestroyingEvent` - 架构销毁中 -- `ArchitectureDestroyedEvent` - 架构已销毁 -- `ArchitectureFailedInitializationEvent` - 架构初始化失败 - -## 在架构中使用事件 - -### 定义事件类 - -```csharp -// 简单事件 -public struct GameStartedEvent { } - -// 带数据的事件 -public struct PlayerDiedEvent -{ - public Vector3 Position; - public string Cause; -} - -// 复杂事件 -public struct LevelCompletedEvent -{ - public int LevelId; - public float CompletionTime; - public int Score; - public List Achievements; -} -``` - -### Model 中发送事件 - -```csharp -public class PlayerModel : AbstractModel -{ - public BindableProperty Health { get; } = new(100); - - protected override void OnInit() - { - // 监听生命值变化 - Health.Register(newHealth => - { - if (newHealth <= 0) - { - // 发送玩家死亡事件 - this.SendEvent(new PlayerDiedEvent - { - Position = Position, - Cause = "Health depleted" - }); - } - }); - } -} -``` - -### System 中发送事件 - -```csharp -public class CombatSystem : AbstractSystem -{ - protected override void OnInit() { } - - public void DealDamage(Character attacker, Character target, int damage) - { - target.Health -= damage; - - // 发送伤害事件 - this.SendEvent(new DamageDealtEvent - { - Attacker = attacker.Name, - Target = target.Name, - Damage = damage - }); - } -} -``` - -### Controller 中注册事件 - -```csharp -public partial class GameController : Node, IController -{ - private IUnRegisterList _unregisterList = new UnRegisterList(); - - public IArchitecture GetArchitecture() => GameArchitecture.Interface; - - public override void _Ready() - { - // 注册多个事件 - this.RegisterEvent(OnGameStarted) - .AddToUnregisterList(_unregisterList); - - this.RegisterEvent(OnPlayerDied) - .AddToUnregisterList(_unregisterList); - - this.RegisterEvent(OnLevelCompleted) - .AddToUnregisterList(_unregisterList); - } - - private void OnGameStarted(GameStartedEvent e) - { - GD.Print("Game started!"); - } - - private void OnPlayerDied(PlayerDiedEvent e) - { - GD.Print($"Player died at {e.Position}: {e.Cause}"); - ShowGameOverScreen(); - } - - private void OnLevelCompleted(LevelCompletedEvent e) - { - GD.Print($"Level {e.LevelId} completed! Score: {e.Score}"); - ShowVictoryScreen(e); - } - - public override void _ExitTree() - { - _unregisterList.UnRegisterAll(); - } -} -``` - -## 高级用法 - -### 1. 事件链式组合 - -```csharp -// 使用 Or 组合多个事件 -var onAnyDamage = new OrEvent() - .Or(onPhysicalDamage) - .Or(onMagicDamage) - .Or(onPoisonDamage); - -onAnyDamage.Register(() => -{ - PlayDamageSound(); -}); -``` - -### 2. 事件过滤 - -```csharp -// 只处理高伤害事件 -this.RegisterEvent(e => -{ - if (e.Damage >= 50) - { - ShowCriticalHitEffect(); - } -}); -``` - -### 3. 事件转发 - -```csharp -public class EventBridge : AbstractSystem -{ - protected override void OnInit() - { - // 将内部事件转发为公共事件 - this.RegisterEvent(e => - { - this.SendEvent(new PublicPlayerDiedEvent - { - PlayerId = e.Id, - Timestamp = DateTime.Now - }); - }); - } -} -``` - -### 4. 临时事件监听 - -```csharp -public class TutorialController : Node, IController -{ - public override void _Ready() - { - // 只监听一次 - IUnRegister unregister = null; - unregister = this.RegisterEvent(e => - { - ShowTutorialComplete(); - unregister?.UnRegister(); // 立即注销 - }); - } -} -``` - -### 5. 条件事件 - -```csharp -public class AchievementSystem : AbstractSystem -{ - private int _killCount = 0; - - protected override void OnInit() - { - this.RegisterEvent(e => - { - _killCount++; - - // 条件满足时发送成就事件 - if (_killCount >= 100) - { - this.SendEvent(new AchievementUnlockedEvent - { - AchievementId = "kill_100_enemies" - }); - } - }); - } -} -``` - -## 生命周期管理 - -### 使用 UnRegisterList - -```csharp -public class MyController : Node, IController -{ - // 统一管理所有注销对象 - private IUnRegisterList _unregisterList = new UnRegisterList(); - - public override void _Ready() - { - // 所有注册都添加到列表 - this.RegisterEvent(OnEvent1) - .AddToUnregisterList(_unregisterList); - - this.RegisterEvent(OnEvent2) - .AddToUnregisterList(_unregisterList); - } - - public override void _ExitTree() - { - // 一次性注销所有 - _unregisterList.UnRegisterAll(); - } -} -``` - -### 使用 Godot 节点生命周期 - -```csharp -public override void _Ready() -{ - // 当节点退出场景树时自动注销 - this.RegisterEvent(OnGameEvent) - .UnRegisterWhenNodeExitTree(this); -} -``` - -## 最佳实践 - -1. **事件命名规范** - - 使用过去式:`PlayerDiedEvent`、`LevelCompletedEvent` - - 使用 `Event` 后缀:便于识别 - - 使用结构体:减少内存分配 - -2. **事件数据设计** - - 只包含必要信息 - - 使用值类型(struct)提高性能 - - 避免传递可变引用 - -3. **避免事件循环** - - 事件处理器中谨慎发送新事件 - - 使用命令打破循环依赖 - -4. **合理使用事件** - - 用于通知状态变化 - - 用于跨模块通信 - - 不用于返回数据(使用 Query) - -5. **注销管理** - - 始终注销事件监听 - - 使用 `IUnRegisterList` 批量管理 - - 利用 Godot 节点生命周期 - -6. **性能考虑** - - 避免频繁触发的事件(如每帧) - - 事件处理器保持轻量 - - 使用结构体事件减少 GC - -## 事件 vs 其他通信方式 - -| 方式 | 适用场景 | 优点 | 缺点 | -|----------------------|--------------|-----------|---------| -| **Event** | 状态变化通知、跨模块通信 | 松耦合、一对多 | 难以追踪调用链 | -| **Command** | 执行操作、修改状态 | 封装逻辑、可撤销 | 单向通信 | -| **Query** | 查询数据 | 职责清晰、有返回值 | 同步调用 | -| **BindableProperty** | UI 数据绑定 | 自动更新、响应式 | 仅限单一属性 | - -## 相关包 - -- [`architecture`](../architecture/README.md) - 提供全局事件系统 -- [`extensions`](../extensions/README.md) - 提供事件扩展方法 -- [`property`](../property/README.md) - 可绑定属性基于事件实现 -- [`controller`](../controller/README.md) - 控制器监听事件 -- [`model`](../model/README.md) - 模型发送事件 -- [`system`](../system/README.md) - 系统发送和监听事件 \ No newline at end of file diff --git a/GFramework.Core/extensions/README.md b/GFramework.Core/extensions/README.md deleted file mode 100644 index 3681d11..0000000 --- a/GFramework.Core/extensions/README.md +++ /dev/null @@ -1,552 +0,0 @@ -# Extensions 包使用说明 - -## 概述 - -Extensions 包提供了一系列扩展方法,简化了框架各个接口的使用。通过扩展方法,可以用更简洁的语法访问框架功能,提高代码可读性和开发效率。 - -## 扩展方法类别 - -### 1. ContextAware 扩展 ([`ContextAwareExtensions.cs`](ContextAwareExtensions.cs)) - -为 [`IContextAware`](../../GFramework.Core.Abstractions/rule/IContextAware.cs) -提供扩展方法,允许直接从实现了 [IContextAware](file:///d:/Project/Rider/GFramework/GFramework.Core.Abstractions/rule/IContextAware.cs) -的对象获取架构组件。 - -#### GetSystem 扩展方法 - -```csharp -public static TSystem? GetSystem(this IContextAware contextAware) - where TSystem : class, ISystem -``` - -**使用示例:** - -```csharp -// 在实现了 IContextAware 的类中使用 -public class PlayerController : IController -{ - public void UpdateUI() - { - // 直接通过 this 调用 - var playerSystem = this.GetSystem(); - var inventorySystem = this.GetSystem(); - } -} -``` - -#### GetModel 扩展方法 - -```csharp -public static TModel? GetModel(this IContextAware contextAware) - where TModel : class, IModel -``` - -**使用示例:** - -```csharp -public class PlayerController : IController -{ - public void UpdateStats() - { - // 获取模型 - var playerModel = this.GetModel(); - var inventoryModel = this.GetModel(); - - // 使用模型数据 - playerModel.Health += 10; - } -} -``` - -#### GetUtility 扩展方法 - -```csharp -public static TUtility? GetUtility(this IContextAware contextAware) - where TUtility : class, IUtility -``` - -**使用示例:** - -```csharp -public class GameModel : AbstractModel, IContextAware -{ - protected override void OnInit() - { - // 获取工具 - var timeUtility = this.GetUtility(); - var storageUtility = this.GetUtility(); - } -} -``` - -#### SendCommand 扩展方法 - -```csharp -// 发送无返回值的命令 -public static void SendCommand(this IContextAware contextAware, ICommand command) - -// 发送带返回值的命令 -public static TResult SendCommand(this IContextAware contextAware, ICommand command) -``` - -**使用示例:** - -```csharp -public class GameController : IController -{ - public void OnStartButtonClicked() - { - // 发送命令实例 - this.SendCommand(new StartGameCommand()); - - // 发送带返回值的命令 - var result = this.SendCommand(new CalculateScoreCommand()); - } -} -``` - -#### SendQuery 扩展方法 - -```csharp -public static TResult SendQuery(this IContextAware contextAware, IQuery query) -``` - -**使用示例:** - -```csharp -public class InventoryController : IController -{ - public void ShowInventory() - { - // 发送查询获取数据 - var items = this.SendQuery(new GetInventoryItemsQuery()); - var gold = this.SendQuery(new GetPlayerGoldQuery()); - - UpdateInventoryUI(items, gold); - } -} -``` - -#### SendEvent 扩展方法 - -```csharp -// 发送无参事件 -public static void SendEvent(this IContextAware contextAware) where T : new() - -// 发送事件实例 -public static void SendEvent(this IContextAware contextAware, T e) where T : class -``` - -**使用示例:** - -```csharp -public class PlayerModel : AbstractModel, IContextAware -{ - public void TakeDamage(int damage) - { - Health -= damage; - - if (Health <= 0) - { - // 方式1:发送无参事件 - this.SendEvent(); - - // 方式2:发送带数据的事件 - this.SendEvent(new PlayerDiedEvent - { - Position = Position, - Cause = "Damage" - }); - } - } -} -``` - -#### RegisterEvent 扩展方法 - -```csharp -public static IUnRegister RegisterEvent(this IContextAware contextAware, Action handler) -``` - -**使用示例:** - -```csharp -public class GameController : IController -{ - private IUnRegisterList _unregisterList = new UnRegisterList(); - - public void Initialize() - { - // 注册事件监听 - this.RegisterEvent(OnGameStarted) - .AddToUnregisterList(_unregisterList); - - this.RegisterEvent(OnPlayerLevelUp) - .AddToUnregisterList(_unregisterList); - } - - private void OnGameStarted(GameStartedEvent e) { } - private void OnPlayerLevelUp(PlayerLevelUpEvent e) { } -} -``` - -#### UnRegisterEvent 扩展方法 - -```csharp -public static void UnRegisterEvent(this IContextAware contextAware, Action onEvent) -``` - -### GetEnvironment 扩展方法 - -```csharp -public static T? GetEnvironment(this IContextAware contextAware) where T : class -public static IEnvironment GetEnvironment(this IContextAware contextAware) -``` - -### 2. Object 扩展 ([`ObjectExtensions.cs`](ObjectExtensions.cs)) - -提供基于运行时类型判断的对象扩展方法,用于简化类型分支、链式调用和架构分派逻辑。 - -#### IfType 扩展方法 - -```csharp -// 最简单的类型判断 -public static bool IfType(this object obj, Action action) - -// 带条件的类型判断 -public static bool IfType( - this object obj, - Func predicate, - Action action -) - -// 条件判断,带不匹配时的处理 -public static void IfType( - this object obj, - Action whenMatch, - Action? whenNotMatch = null -) -``` - -**使用示例:** - -```csharp -object obj = new MyRule(); - -// 简单类型判断 -bool executed = obj.IfType(rule => -{ - rule.Initialize(); -}); - -// 带条件的类型判断 -obj.IfType( - r => r.Enabled, // 条件 - r => r.Execute() // 执行动作 -); - -// 带不匹配处理的类型判断 -obj.IfType( - rule => rule.Execute(), - other => Logger.Warn($"Unsupported type: {other.GetType()}") -); -``` - -#### IfType 扩展方法 - -```csharp -public static TResult? IfType( - this object obj, - Func func -) -``` - -**使用示例:** - -```csharp -object obj = new MyRule { Name = "TestRule" }; - -string? name = obj.IfType(r => r.Name); -``` - -#### As 和 Do 扩展方法 - -```csharp -// 安全类型转换 -public static T? As(this object obj) where T : class - -// 流式调用 -public static T Do(this T obj, Action action) -``` - -**使用示例:** - -```csharp -// 安全类型转换 -obj.As() - ?.Execute(); - -// 流式调用 -obj.As() - ?.Do(r => r.Initialize()) - ?.Do(r => r.Execute()); - -// 组合使用 -obj.As() - ?.Do(rule => - { - if (rule.Enabled) - rule.Execute(); - }); -``` - -#### SwitchType 扩展方法 - -```csharp -public static void SwitchType( - this object obj, - params (Type type, Action action)[] handlers -) -``` - -**使用示例:** - -```csharp -obj.SwitchType( - (typeof(IRule), o => HandleRule((IRule)o)), - (typeof(ISystem), o => HandleSystem((ISystem)o)), - (typeof(IModel), o => HandleModel((IModel)o)) -); -``` - -### 3. OrEvent 扩展 ([`OrEventExtensions.cs`](OrEventExtensions.cs)) - -为 [`IEvent`](../../GFramework.Core.Abstractions/events/IEvent.cs) 提供事件组合功能。 - -#### OrEventExtensions - -```csharp -public static OrEvent Or(this IEvent self, IEvent e) -``` - -**使用示例:** - -```csharp -// 组合多个事件:当任意一个触发时执行 -var onAnyInput = onKeyPressed.Or(onMouseClicked).Or(onTouchDetected); - -onAnyInput.Register(() => -{ - GD.Print("Any input detected!"); -}); - -// 链式组合 -var onAnyDamage = onPhysicalDamage - .Or(onMagicDamage) - .Or(onPoisonDamage); -``` - -### 4. UnRegisterList 扩展 ([`UnRegisterListExtension.cs`](UnRegisterListExtension.cs)) - -为 [`IUnRegister`](../events/IUnRegister.cs) 和 [`IUnRegisterList`](../events/IUnRegisterList.cs) 提供批量管理功能。 - -#### UnRegisterListExtension - -```csharp -// 添加到注销列表 -public static void AddToUnregisterList(this IUnRegister self, - IUnRegisterList unRegisterList) - -// 批量注销 -public static void UnRegisterAll(this IUnRegisterList self) -``` - -**使用示例:** - -```csharp -public class ComplexController : IController -{ - private IUnRegisterList _unregisterList = new UnRegisterList(); - - public void Initialize() - { - // 所有注册都添加到列表中 - this.RegisterEvent(OnEvent1) - .AddToUnregisterList(_unregisterList); - - this.RegisterEvent(OnEvent2) - .AddToUnregisterList(_unregisterList); - - this.GetModel().Property1.Register(OnProperty1Changed) - .AddToUnregisterList(_unregisterList); - - this.GetModel().Property2.Register(OnProperty2Changed) - .AddToUnregisterList(_unregisterList); - } - - public void Cleanup() - { - // 一次性注销所有 - _unregisterList.UnRegisterAll(); - } -} -``` - -## 完整使用示例 - -### Controller 示例 - -```csharp -public partial class GameplayController : IController -{ - private IUnRegisterList _unregisterList = new UnRegisterList(); - - public void Initialize() - { - // 使用扩展方法获取 Model - var playerModel = this.GetModel(); - var gameModel = this.GetModel(); - - // 使用扩展方法注册事件 - this.RegisterEvent(OnGameStarted) - .AddToUnregisterList(_unregisterList); - - // 监听可绑定属性 - playerModel.Health.Register(OnHealthChanged) - .AddToUnregisterList(_unregisterList); - } - - public void Process(double delta) - { - // 发送命令 - this.SendCommand(new AttackCommand(targetId: 1)); - - // 发送查询 - var hasPotion = this.SendQuery(new HasItemQuery("health_potion")); - if (hasPotion) - { - this.SendCommand(); - } - } - - private void OnGameStarted(GameStartedEvent e) - { - Console.WriteLine("Game started!"); - } - - private void OnHealthChanged(int health) - { - UpdateHealthBar(health); - } - - public void Cleanup() - { - _unregisterList.UnRegisterAll(); - } -} -``` - -### Command 示例 - -```csharp -public class ComplexGameCommand : AbstractCommand -{ - protected override void OnExecute() - { - // 获取多个组件 - var playerModel = this.GetModel(); - var gameSystem = this.GetSystem(); - var timeUtility = this.GetUtility(); - - // 执行业务逻辑 - var currentTime = timeUtility.GetCurrentTime(); - gameSystem.ProcessGameLogic(playerModel, currentTime); - - // 发送事件通知 - this.SendEvent(new GameStateChangedEvent()); - - // 可以发送其他命令(谨慎使用) - this.SendCommand(); - } -} -``` - -### System 示例 - -```csharp -public class AchievementSystem : AbstractSystem -{ - protected override void OnInit() - { - // 注册事件监听 - this.RegisterEvent(OnEnemyKilled); - this.RegisterEvent(OnLevelCompleted); - } - - private void OnEnemyKilled(EnemyKilledEvent e) - { - // 获取模型 - var playerModel = this.GetModel(); - playerModel.EnemyKillCount++; - - // 检查成就 - if (playerModel.EnemyKillCount >= 100) - { - // 发送成就解锁事件 - this.SendEvent(new AchievementUnlockedEvent - { - AchievementId = "kill_100_enemies" - }); - } - } - - private void OnLevelCompleted(LevelCompletedEvent e) - { - // 发送查询 - var completionTime = this.SendQuery(new GetLevelTimeQuery(e.LevelId)); - - if (completionTime < 60) - { - this.SendEvent(new AchievementUnlockedEvent - { - AchievementId = "speed_runner" - }); - } - } -} -``` - -## 扩展方法的优势 - -1. **简洁的语法** - :不需要显式调用 [GetContext()](file:///d:/Project/Rider/GFramework/GFramework.Core.Abstractions/rule/IContextAware.cs#L13-L15) -2. **类型安全**:编译时检查类型 -3. **可读性高**:代码意图更清晰 -4. **智能提示**:IDE 可以提供完整的自动补全 -5. **链式调用**:支持流式编程风格 - -## 注意事项 - -1. **确保引用命名空间:** - ```csharp - using GFramework.Core.extensions; - ``` - -2. **理解扩展方法本质:** - - 扩展方法是静态方法的语法糖 - - 不会改变原始类型的结构 - - 仅在编译时解析 - -3. **性能考虑:** - - 扩展方法本身无性能开销 - - 实际调用的是底层方法 - -## 相关包 - -- [`architecture`](../architecture/README.md) - 扩展方法最终调用架构方法 -- [`command`](../command/README.md) - 命令发送扩展 -- [`query`](../query/README.md) - 查询发送扩展 -- [`events`](../events/README.md) - 事件注册和 Or 组合扩展 -- [`model`](../model/README.md) - 模型获取扩展 -- [`system`](../system/README.md) - 系统获取扩展 -- [`utility`](../utility/README.md) - 工具获取扩展 \ No newline at end of file diff --git a/GFramework.Core/ioc/README.md b/GFramework.Core/ioc/README.md deleted file mode 100644 index 9314e6f..0000000 --- a/GFramework.Core/ioc/README.md +++ /dev/null @@ -1,689 +0,0 @@ -# IoC 包使用说明 - -## 概述 - -IoC(Inversion of Control,控制反转)包提供了一个轻量级的依赖注入容器,用于管理框架中各种组件的注册和获取。通过 IoC -容器,可以实现组件间的解耦,便于测试和维护。 - -## 核心类 - -### [`IocContainer`](IocContainer.cs) - -IoC 容器类,负责管理对象的注册和获取。 - -**主要功能:** - -- 注册实例到容器 -- 从容器中获取实例 -- 类型安全的依赖管理 -- 线程安全操作 -- 容器冻结保护 - -## 核心方法 - -### 1. Register 和 Register(Type, object) - -注册一个实例到容器中。 - -```csharp -public void Register(T instance) -public void Register(Type type, object instance) -``` - -**参数:** - -- `instance`: 要注册的实例对象 -- `type`: 要注册的类型(重载方法) - -**使用示例:** - -```csharp -var container = new IocContainer(); - -// 注册各种类型的实例 -container.Register(new PlayerModel()); -container.Register(new GameSystem()); -container.Register(new StorageUtility()); -``` - -### 2. RegisterSingleton - -注册单例实例到容器中。一个类型只允许一个实例。 - -```csharp -public void RegisterSingleton(T instance) -``` - -**参数:** - -- `instance`: 要注册的单例实例 - -**使用示例:** - -```csharp -var container = new IocContainer(); - -// 注册单例 -container.RegisterSingleton(new PlayerModel()); -``` - -### 3. RegisterPlurality - -注册多个实例,将实例注册到其实现的所有接口和具体类型上。 - -```csharp -public void RegisterPlurality(object instance) -``` - -**参数:** - -- `instance`: 要注册的实例 - -### 4. RegisterSystem - -注册系统实例,将其绑定到其所有实现的接口上。 - -```csharp -public void RegisterSystem(ISystem system) -``` - -**参数:** - -- `system`: 系统实例对象 - -### 5. Get 和 GetAll - -从容器中获取指定类型的实例。 - -```csharp -public T? Get() where T : class -public IReadOnlyList GetAll() where T : class -``` - -**返回值:** - -- `Get`: 返回指定类型的实例,如果未找到则返回 `null` -- `GetAll`: 返回指定类型的所有实例列表,如果未找到则返回空数组 - -**使用示例:** - -```csharp -// 获取已注册的实例 -var playerModel = container.Get(); -var gameSystems = container.GetAll(); - -// 如果类型未注册,Get 返回 null,GetAll 返回空数组 -var unknownService = container.Get(); // null -``` - -### 6. GetRequired - -获取指定类型的必需实例,如果没有注册或注册了多个实例会抛出异常。 - -```csharp -public T GetRequired() where T : class -``` - -**返回值:** - -- 返回找到的唯一实例 - -### 7. GetAllSorted - -获取并排序(系统调度专用)。 - -```csharp -public IReadOnlyList GetAllSorted(Comparison comparison) where T : class -``` - -**参数:** - -- `comparison`: 比较器委托,定义排序规则 - -**返回值:** - -- 按指定方式排序后的实例列表 - -## 在框架中的使用 - -### Architecture 中的应用 - -IoC 容器是 [`Architecture`](../architecture/Architecture.cs) 类的核心组件,用于管理所有的 System、Model 和 Utility。 - -```csharp -public abstract class Architecture : IArchitecture -{ - // 内置 IoC 容器 - private readonly IocContainer _mContainer = new(); - - // 注册系统 - public void RegisterSystem(TSystem system) where TSystem : ISystem - { - system.SetArchitecture(this); - _mContainer.Register(system); // 注册到容器 - // ... - } - - // 获取系统 - public TSystem GetSystem() where TSystem : class, ISystem - => _mContainer.Get(); // 从容器获取 - - // Model 和 Utility 同理 -} -``` - -### 注册组件到容器 - -```csharp -public class GameArchitecture : Architecture -{ - protected override void Init() - { - // 这些方法内部都使用 IoC 容器 - - // 注册 Model(存储游戏数据) - RegisterModel(new PlayerModel()); - RegisterModel(new InventoryModel()); - - // 注册 System(业务逻辑) - RegisterSystem(new GameplaySystem()); - RegisterSystem(new SaveSystem()); - - // 注册 Utility(工具类) - RegisterUtility(new TimeUtility()); - RegisterUtility(new StorageUtility()); - } -} -``` - -### 从容器获取组件 - -```csharp -// 通过扩展方法间接使用 IoC 容器 -public class PlayerController : IController -{ - public void Start() - { - // GetModel 内部调用 Architecture.GetModel - // Architecture.GetModel 内部调用 IocContainer.Get - var playerModel = this.GetModel(); - - var gameplaySystem = this.GetSystem(); - var timeUtility = this.GetUtility(); - } -} -``` - -## 工作原理 - -### 内部实现 - -```csharp -public class IocContainer -{ - // 使用字典存储类型到实例集合的映射 - private readonly Dictionary> _typeIndex = new(); - private readonly HashSet _objects = []; - private readonly ReaderWriterLockSlim _lock = new(LockRecursionPolicy.NoRecursion); - private volatile bool _frozen = false; - - public void Register(T instance) - { - // 获取写锁以确保线程安全 - _lock.EnterWriteLock(); - try - { - RegisterInternal(typeof(T), instance!); - } - finally - { - _lock.ExitWriteLock(); - } - } - - public T? Get() where T : class - { - _lock.EnterReadLock(); - try - { - if (_typeIndex.TryGetValue(typeof(T), out var set) && set.Count > 0) - { - var result = set.First() as T; - return result; - } - - return null; - } - finally - { - _lock.ExitReadLock(); - } - } - - private void RegisterInternal(Type type, object instance) - { - if (_frozen) throw new InvalidOperationException("IocContainer is frozen"); - - _objects.Add(instance); - - if (!_typeIndex.TryGetValue(type, out var set)) - { - set = []; - _typeIndex[type] = set; - } - - set.Add(instance); - } -} -``` - -### 线程安全机制 - -容器使用 [ReaderWriterLockSlim](xref:System.Threading.ReaderWriterLockSlim) 来确保线程安全操作,允许多个线程同时读取,但在写入时阻止其他线程访问。 - -### 注册流程 - -``` -用户代码 - ↓ -RegisterSystem(system) - ↓ -IocContainer.Register(system) - ↓ -加写锁 -> Dictionary[typeof(T)] 添加实例到HashSet -``` - -### 获取流程 - -``` -用户代码 - ↓ -this.GetSystem() - ↓ -Architecture.GetSystem() - ↓ -IocContainer.Get() - ↓ -加读锁 -> Dictionary.TryGetValue(typeof(T)) 获取HashSet - ↓ -返回HashSet中第一个实例或 null -``` - -## 使用示例 - -### 基础使用 - -```csharp -// 1. 创建容器 -var container = new IocContainer(); - -// 2. 注册服务 -var playerService = new PlayerService(); -container.Register(playerService); - -// 3. 获取服务 -var service = container.Get(); -service.DoSomething(); -``` - -### 接口和实现分离 - -```csharp -// 定义接口 -public interface IDataService -{ - void SaveData(string data); - string LoadData(); -} - -// 实现类 -public class LocalDataService : IDataService -{ - public void SaveData(string data) { /* 本地存储 */ } - public string LoadData() { /* 本地加载 */ return ""; } -} - -public class CloudDataService : IDataService -{ - public void SaveData(string data) { /* 云端存储 */ } - public string LoadData() { /* 云端加载 */ return ""; } -} - -// 注册(可以根据配置选择不同实现) -var container = new IocContainer(); - -#if CLOUD_SAVE -container.Register(new CloudDataService()); -#else -container.Register(new LocalDataService()); -#endif - -// 使用(不需要关心具体实现) -var dataService = container.Get(); -dataService.SaveData("game data"); -``` - -### 注册多个实现 - -```csharp -var container = new IocContainer(); - -// 注册多个相同接口的不同实现 -container.Register(new LocalDataService()); -container.Register(new CloudDataService()); - -// 获取单个实例(返回第一个) -var singleService = container.Get(); // 返回第一个注册的实例 - -// 获取所有实例 -var allServices = container.GetAll(); // 返回两个实例的列表 -``` - -## 其他实用方法 - -### `Contains()` - -检查容器中是否包含指定类型的实例。 - -```csharp -public bool Contains() where T : class -``` - -**参数:** - -- 无泛型参数 - -**返回值:** - -- 如果容器中包含指定类型的实例则返回 `true`,否则返回 `false` - -**使用示例:** - -```csharp -var container = new IocContainer(); - -// 检查服务是否已注册 -if (container.Contains()) -{ - Console.WriteLine("Player service is available"); -} - -// 根据检查结果决定是否注册 -if (!container.Contains()) -{ - container.Register(new SettingsService()); -} -``` - -**应用场景:** - -- 条件注册服务 -- 检查依赖是否可用 -- 动态功能开关 - -### `ContainsInstance(object instance)` - -判断容器中是否包含某个具体的实例对象。 - -```csharp -public bool ContainsInstance(object instance) -``` - -**参数:** - -- `instance`:待查询的实例对象 - -**返回值:** - -- 若容器中包含该实例则返回 `true`,否则返回 `false` - -**使用示例:** - -```csharp -var container = new IocContainer(); - -var service = new MyService(); -container.Register(service); - -// 检查特定实例是否在容器中 -if (container.ContainsInstance(service)) -{ - Console.WriteLine("This instance is registered in the container"); -} - -// 检查另一个实例 -var anotherService = new MyService(); -if (!container.ContainsInstance(anotherService)) -{ - Console.WriteLine("This instance is not in the container"); -} -``` - -**应用场景:** - -- 避免重复注册同一实例 -- 检查对象是否已被管理 -- 调试和日志记录 - -### `Clear()` - -清空容器中的所有实例。 - -```csharp -public void Clear() -``` - -**使用示例:** - -```csharp -var container = new IocContainer(); - -// 注册多个服务 -container.Register(new Service1()); -container.Register(new Service2()); -container.Register(new Service3()); - -// 清空容器 -container.Clear(); - -// 检查是否清空成功 -Console.WriteLine($"Contains IService1: {container.Contains()}"); // False -Console.WriteLine($"Contains IService2: {container.Contains()}"); // False -``` - -**应用场景:** - -- 重置容器状态 -- 内存清理 -- 测试环境准备 - -**注意事项:** - -- 容器冻结后也可以调用 `Clear()` 方法 -- 清空后,所有已注册的实例都将丢失 -- 不会自动清理已注册对象的其他引用 - -## 设计特点 - -### 1. 简单轻量 - -- 支持多种注册方式:普通注册、单例注册、多实例注册 -- 基于字典和哈希集实现,性能高效 -- 无复杂的依赖解析逻辑 - -### 2. 手动注册 - -- 需要显式注册每个组件 -- 不支持自动依赖注入 -- 完全可控的组件生命周期 - -### 3. 多实例支持 - -- 每个类型可以注册多个实例 -- 提供 [GetAll](file:///d:/Project/Rider/GFramework/GFramework.Core/ioc/IocContainer.cs#L244-L261) 方法获取所有实例 -- 提供 [Get](file:///d:/Project/Rider/GFramework/GFramework.Core/ioc/IocContainer.cs#L208-L225) 方法获取单个实例 - -### 4. 类型安全 - -- 基于泛型,编译时类型检查 -- 避免字符串键导致的错误 -- IDE 友好,支持自动补全 - -### 5. 线程安全 - -- 使用读写锁确保多线程环境下的安全操作 -- 读操作可以并发执行 -- 写操作独占锁,防止并发修改冲突 - -### 6. 容器冻结 - -- 提供 [Freeze](file:///d:/Project/Rider/GFramework/GFramework.Core/ioc/IocContainer.cs#L359-L372) 方法,防止进一步修改容器内容 -- 防止在初始化后意外修改注册内容 - -## 与其他 IoC 容器的区别 - -### 本框架的 IocContainer - -```csharp -// 简单直接 -var container = new IocContainer(); -container.Register(new MyService()); -var service = container.Get(); -``` - -**特点:** - -- ✅ 简单易用 -- ✅ 性能高 -- ✅ 线程安全 -- ✅ 支持多实例 -- ❌ 不支持构造函数注入 -- ❌ 不支持自动解析依赖 -- ❌ 不支持生命周期管理(Transient/Scoped/Singleton) - -### 完整的 IoC 框架(如 Autofac、Zenject) - -```csharp -// 复杂但功能强大 -var builder = new ContainerBuilder(); -builder.RegisterType().As().SingleInstance(); -builder.RegisterType().WithParameter("config", config); -var container = builder.Build(); - -// 自动解析依赖 -var controller = container.Resolve(); -``` - -**特点:** - -- ✅ 自动依赖注入 -- ✅ 生命周期管理 -- ✅ 复杂场景支持 -- ❌ 学习成本高 -- ❌ 性能开销大 - -## 最佳实践 - -### 1. 在架构初始化时注册 - -```csharp -public class GameArchitecture : Architecture -{ - protected override void Init() - { - // 按顺序注册组件 - // 1. 工具类(无依赖) - RegisterUtility(new TimeUtility()); - RegisterUtility(new StorageUtility()); - - // 2. 模型(可能依赖工具) - RegisterModel(new PlayerModel()); - RegisterModel(new GameModel()); - - // 3. 系统(可能依赖模型和工具) - RegisterSystem(new GameplaySystem()); - RegisterSystem(new SaveSystem()); - } -} -``` - -### 2. 使用接口类型注册 - -```csharp -// ❌ 不推荐:直接使用实现类 -RegisterSystem(new ConcreteSystem()); -var system = GetSystem(); - -// ✅ 推荐:使用接口 -RegisterSystem(new ConcreteSystem()); -var system = GetSystem(); -``` - -### 3. 避免运行时频繁注册 - -```csharp -// ❌ 不好:游戏运行时频繁注册 -void Update() -{ - RegisterService(new TempService()); // 每帧创建 -} - -// ✅ 好:在初始化时一次性注册 -protected override void Init() -{ - RegisterService(new PersistentService()); -} -``` - -### 4. 检查 null 返回值 - -```csharp -// 获取可能不存在的服务 -var service = container.Get(); -if (service != null) -{ - service.DoSomething(); -} -else -{ - GD.Print("Service not registered!"); -} -``` - -### 5. 合理使用容器冻结 - -```csharp -// 在架构初始化完成后冻结容器,防止意外修改 -protected override void OnInit() -{ - // 注册所有组件 - RegisterModel(new PlayerModel()); - RegisterSystem(new GameSystem()); - // ... - - // 冻结容器 - Container.Freeze(); // 此后无法再注册新组件 -} -``` - -## 注意事项 - -1. **线程安全操作**:容器内部使用读写锁确保线程安全,无需额外同步 - -2. **容器冻结**:一旦调用 [Freeze](file:///d:/Project/Rider/GFramework/GFramework.Core/ioc/IocContainer.cs#L359-L372) - 方法,将不能再注册新实例 - -3. **单例注册限制 - **:[RegisterSingleton](file:///d:/Project/Rider/GFramework/GFramework.Core/ioc/IocContainer.cs#L84-L106) - 方法确保一个类型只能有一个实例,重复注册会抛出异常 - -4. **内存管理**:容器持有的实例不会自动释放,需要注意内存泄漏问题 - -5. **注册顺序**:组件的依赖关系需要手动保证,先注册被依赖的组件 - -## 相关包 - -- [`architecture`](../architecture/README.md) - 使用 IoC 容器管理所有组件 -- [`model`](../model/README.md) - Model 通过 IoC 容器注册和获取 -- [`system`](../system/README.md) - System 通过 IoC 容器注册和获取 -- [`utility`](../utility/README.md) - Utility 通过 IoC 容器注册和获取 \ No newline at end of file diff --git a/GFramework.Core/logging/README.md b/GFramework.Core/logging/README.md deleted file mode 100644 index 6f93aac..0000000 --- a/GFramework.Core/logging/README.md +++ /dev/null @@ -1,364 +0,0 @@ -# Logging 包使用说明 - -## 概述 - -Logging 包提供了灵活的日志系统,支持多级别日志记录。默认日志级别为 `Info`,确保框架的关键操作都能被记录下来。 - -## 核心接口 - -### [ILogger](ILogger.cs) - -日志记录器接口,定义了日志记录的基本功能。 - -**核心方法:** - -```csharp -// 日志级别检查 -bool IsTraceEnabled(); -bool IsDebugEnabled(); -bool IsInfoEnabled(); -bool IsWarnEnabled(); -bool IsErrorEnabled(); -bool IsFatalEnabled(); - -// 记录日志 -void Trace(string msg); -void Trace(string format, object arg); -void Trace(string format, object arg1, object arg2); -void Trace(string format, params object[] arguments); -void Trace(string msg, Exception t); - -void Debug(string msg); -void Debug(string format, object arg); -void Debug(string format, object arg1, object arg2); -void Debug(string format, params object[] arguments); -void Debug(string msg, Exception t); - -void Info(string msg); -void Info(string format, object arg); -void Info(string format, object arg1, object arg2); -void Info(string format, params object[] arguments); -void Info(string msg, Exception t); - -void Warn(string msg); -void Warn(string format, object arg); -void Warn(string format, object arg1, object arg2); -void Warn(string format, params object[] arguments); -void Warn(string msg, Exception t); - -void Error(string msg); -void Error(string format, object arg); -void Error(string format, object arg1, object arg2); -void Error(string format, params object[] arguments); -void Error(string msg, Exception t); - -void Fatal(string msg); -void Fatal(string format, object arg); -void Fatal(string format, object arg1, object arg2); -void Fatal(string format, params object[] arguments); -void Fatal(string msg, Exception t); - -// 获取日志器名称 -string Name(); -``` - -### [ILoggerFactory](ILoggerFactory.cs) - -日志工厂接口,用于创建日志记录器实例。 - -**核心方法:** - -```csharp -ILogger GetLogger(string name, LogLevel minLevel = LogLevel.Info); -``` - -### [ILoggerFactoryProvider](ILoggerFactoryProvider.cs) - -日志工厂提供程序接口,用于获取日志工厂。 - -**核心方法:** - -```csharp -ILoggerFactory GetLoggerFactory(); -ILogger CreateLogger(string name); -``` - -### [LogLevel](LogLevel.cs) - -日志级别枚举。 - -```csharp -public enum LogLevel -{ - Trace = 0, // 最详细的跟踪信息 - Debug = 1, // 调试信息 - Info = 2, // 一般信息(默认级别) - Warning = 3, // 警告信息 - Error = 4, // 错误信息 - Fatal = 5 // 致命错误 -} -``` - -## 核心类 - -### [AbstractLogger](AbstractLogger.cs) - -抽象日志基类,封装了日志级别判断、格式化与异常处理逻辑。平台日志器只需实现 `Write` 方法即可。 - -**使用示例:** - -```csharp -public class CustomLogger : AbstractLogger -{ - public CustomLogger(string? name = null, LogLevel minLevel = LogLevel.Info) - : base(name, minLevel) - { - } - - protected override void Write(LogLevel level, string message, Exception? exception) - { - // 自定义日志输出逻辑 - var logMessage = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [{level}] {message}"; - if (exception != null) - logMessage += $"\n{exception}"; - - Console.WriteLine(logMessage); - } -} -``` - -### [ConsoleLogger](ConsoleLogger.cs) - -控制台日志记录器实现,支持彩色输出。 - -**使用示例:** - -```csharp -// 创建控制台日志记录器 -var logger = new ConsoleLogger("MyLogger", LogLevel.Debug); - -// 记录不同级别的日志 -logger.Info("应用程序启动"); -logger.Debug("调试信息"); -logger.Warn("警告信息"); -logger.Error("错误信息"); -logger.Fatal("致命错误"); -``` - -**输出格式:** - -``` -[2025-01-09 01:40:00.000] INFO [MyLogger] 应用程序启动 -[2025-01-09 01:40:01.000] DEBUG [MyLogger] 调试信息 -[2025-01-09 01:40:02.000] WARN [MyLogger] 警告信息 -``` - -**日志级别颜色:** - -- **Trace**: 深灰色 -- **Debug**: 青色 -- **Info**: 白色 -- **Warning**: 黄色 -- **Error**: 红色 -- **Fatal**: 洋红色 - -**构造函数参数:** - -- `name`:日志器名称,默认为 "ROOT" -- `minLevel`:最低日志级别,默认为 LogLevel.Info -- `writer`:TextWriter 输出流,默认为 Console.Out -- `useColors`:是否使用颜色,默认为 true(仅在输出到控制台时生效) - -### [ConsoleLoggerFactory](ConsoleLoggerFactory.cs) - -控制台日志工厂,用于创建控制台日志记录器实例。 - -**使用示例:** - -```csharp -var factory = new ConsoleLoggerFactory(); -var logger = factory.GetLogger("MyModule", LogLevel.Debug); -logger.Info("日志记录器创建成功"); -``` - -### [ConsoleLoggerFactoryProvider](ConsoleLoggerFactoryProvider.cs) - -控制台日志工厂提供程序实现。 - -**使用示例:** - -```csharp -var provider = new ConsoleLoggerFactoryProvider(); -provider.MinLevel = LogLevel.Debug; // 设置最低日志级别 -var logger = provider.CreateLogger("MyApp"); -logger.Info("应用程序启动"); -``` - -### [LoggerFactoryResolver](LoggerFactoryResolver.cs) - -日志工厂提供程序解析器,用于管理和提供日志工厂提供程序实例。 - -**使用示例:** - -```csharp -// 设置日志工厂提供程序 -LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider(); - -// 设置最小日志级别 -LoggerFactoryResolver.MinLevel = LogLevel.Debug; - -// 获取日志记录器 -var logger = LoggerFactoryResolver.Provider.CreateLogger("MyApp"); -logger.Info("应用程序启动"); -``` - -## 在架构中使用日志 - -### 1. 在 Architecture 中使用 - -```csharp -public class GameArchitecture : Architecture -{ - protected override void Init() - { - var logger = LoggerFactoryResolver.Provider.CreateLogger("GameArchitecture"); - logger.Info("游戏架构初始化开始"); - - RegisterModel(new PlayerModel()); - RegisterSystem(new GameSystem()); - - logger.Info("游戏架构初始化完成"); - } -} -``` - -### 2. 在 System 中使用 - -```csharp -public class CombatSystem : AbstractSystem -{ - protected override void OnInit() - { - var logger = LoggerFactoryResolver.Provider.CreateLogger("CombatSystem"); - logger.Info("战斗系统初始化完成"); - } - - protected override void OnDestroy() - { - var logger = LoggerFactoryResolver.Provider.CreateLogger("CombatSystem"); - logger.Info("战斗系统已销毁"); - } -} -``` - -### 3. 在 Model 中使用 - -```csharp -public class PlayerModel : AbstractModel -{ - protected override void OnInit() - { - var logger = LoggerFactoryResolver.Provider.CreateLogger("PlayerModel"); - logger.Info("玩家模型初始化完成"); - } -} -``` - -### 4. 自定义日志级别 - -```csharp -public class DebugLogger : AbstractLogger -{ - public DebugLogger() : base("Debug", LogLevel.Debug) - { - } - - protected override void Write(LogLevel level, string message, Exception? exception) - { - // 只输出调试及更高级别的日志 - if (level >= LogLevel.Debug) - { - Console.WriteLine($"[{level}] {message}"); - if (exception != null) - Console.WriteLine(exception); - } - } -} -``` - -## 日志级别说明 - -| 级别 | 说明 | 使用场景 | -|-------------|----------|-------------------| -| **Trace** | 最详细的跟踪信息 | 调试复杂的执行流程,记录函数调用等 | -| **Debug** | 调试信息 | 开发阶段,记录变量值、流程分支等 | -| **Info** | 一般信息 | 记录重要的业务流程和系统状态 | -| **Warning** | 警告信息 | 可能的问题但不中断程序执行 | -| **Error** | 错误信息 | 影响功能但不致命的问题 | -| **Fatal** | 致命错误 | 导致程序无法继续运行的严重错误 | - -## 最佳实践 - -1. **使用合适的日志级别**: - - 使用 `Info` 记录重要业务流程 - - 使用 `Debug` 记录调试信息 - - 使用 `Warning` 记录异常情况 - - 使用 `Error` 记录错误但不影响程序运行 - - 使用 `Fatal` 记录严重错误 - -2. **提供上下文信息**: - ```csharp - logger.Info($"用户登录成功: UserId={userId}, UserName={userName}"); - ``` - -3. **异常日志记录**: - ```csharp - try - { - // 业务逻辑 - } - catch (Exception ex) - { - logger.Error("数据库操作失败", ex); - } - ``` - -4. **分类使用日志**: - ```csharp - var dbLogger = LoggerFactoryResolver.Provider.CreateLogger("Database"); - var netLogger = LoggerFactoryResolver.Provider.CreateLogger("Network"); - - dbLogger.Info("查询用户数据"); - netLogger.Debug("发送HTTP请求"); - ``` - -5. **在框架组件中合理使用日志**: - ```csharp - // 在系统初始化时记录 - var logger = LoggerFactoryResolver.Provider.CreateLogger("System"); - logger.Info("系统初始化完成"); - ``` - -## 注意事项 - -1. **日志级别检查**: - - 每个日志方法都会自动检查日志级别 - - 如果当前级别低于最小级别,不会输出日志 - -2. **格式化参数**: - - 支持字符串格式化参数 - - 支持异常信息传递 - -3. **ConsoleLogger 的额外参数**: - - ConsoleLogger 现在支持自定义TextWriter输出流 - - 支持禁用颜色输出的功能(useColors参数) - -## 相关包 - -- [architecture](../architecture/README.md) - 架构核心,使用日志系统记录生命周期事件 -- [property](../property/README.md) - 可绑定属性基于事件系统实现 -- [extensions](../extensions/README.md) - 提供便捷的扩展方法 - ---- - -**许可证**: Apache 2.0 \ No newline at end of file diff --git a/GFramework.Core/model/README.md b/GFramework.Core/model/README.md deleted file mode 100644 index df29049..0000000 --- a/GFramework.Core/model/README.md +++ /dev/null @@ -1,184 +0,0 @@ -# Model 包使用说明 - -## 概述 - -Model 包定义了数据模型层的接口和基类。Model 是 MVC 架构中的 M 层,负责管理应用程序的数据和状态。Model -层应该只包含数据和简单的数据逻辑,不包含复杂的业务逻辑。 - -## 核心接口 - -### [`IModel`](IModel.cs) - -模型接口,定义了模型的基本行为和功能。 - -**继承的能力接口:** - -- [`IContextAware`](../rule/IContextAware.cs) - 上下文感知接口 -- [`ILogAware`](../rule/ILogAware.cs) - 日志感知接口 - -**核心方法:** - -```csharp -void Init(); // 初始化模型 -void OnArchitecturePhase(ArchitecturePhase phase); // 处理架构阶段事件 -``` - -### [`ICanGetModel`](ICanGetModel.cs) - -标记接口,表示实现者可以获取模型。继承自 [`IBelongToArchitecture`](../rule/IBelongToArchitecture.cs)。 - -## 核心类 - -### [`AbstractModel`](AbstractModel.cs) - -抽象模型基类,实现IModel接口,提供模型的基础实现。该类继承自[ -`ContextAwareBase`](file:///d:/Project/Rider/GFramework/GFramework.Core/rule/ContextAwareBase.cs#L11-L37),提供了上下文感知能力。 - -**使用示例:** - -```csharp -public class PlayerModel : AbstractModel -{ - // 使用 BindableProperty 定义可监听的属性 - public BindableProperty Name { get; } = new("Player"); - public BindableProperty Level { get; } = new(1); - public BindableProperty Health { get; } = new(100); - public BindableProperty MaxHealth { get; } = new(100); - - protected override void OnInit() - { - // 监听生命值变化 - Health.Register(newHealth => - { - if (newHealth <= 0) - { - this.SendEvent(new PlayerDiedEvent()); - } - }); - } - - public override void OnArchitecturePhase(ArchitecturePhase phase) - { - switch (phase) - { - case ArchitecturePhase.Initializing: - // 架构初始化阶段的处理 - break; - case ArchitecturePhase.Ready: - // 架构就绪阶段的处理 - break; - // ... 其他阶段处理 - } - } -} -``` - -## Model 的职责 - -### ✅ 应该做的事 - -1. **存储数据和状态** -2. **提供数据访问接口** -3. **监听自身属性变化并做出响应** -4. **发送数据变化事件** -5. **处理架构生命周期事件** - -### ❌ 不应该做的事 - -1. **不包含复杂业务逻辑** - 业务逻辑应该在 System 中 -2. **不直接依赖其他 Model** - 通过 Command 协调 -3. **不包含 UI 逻辑** - UI 逻辑应该在 Controller 中 - -## 常见 Model 示例 - -### 玩家数据模型 - -```csharp -public class PlayerModel : AbstractModel -{ - public BindableProperty PlayerId { get; } = new(""); - public BindableProperty PlayerName { get; } = new("Player"); - public BindableProperty Level { get; } = new(1); - public BindableProperty Health { get; } = new(100); - public BindableProperty MaxHealth { get; } = new(100); - public BindableProperty Gold { get; } = new(0); - - public Vector3 Position { get; set; } - - protected override void OnInit() - { - Health.Register(hp => - { - if (hp <= 0) - { - this.SendEvent(new PlayerDiedEvent()); - } - }); - } - - public override void OnArchitecturePhase(ArchitecturePhase phase) - { - switch (phase) - { - case ArchitecturePhase.Ready: - // 模型准备好后的处理 - _log?.Log("PlayerModel is ready."); - break; - default: - break; - } - } -} -``` - -### 游戏状态模型 - -```csharp -public class GameModel : AbstractModel -{ - public BindableProperty State { get; } = new(GameState.Menu); - public BindableProperty Score { get; } = new(0); - public BindableProperty HighScore { get; } = new(0); - public BindableProperty CurrentLevel { get; } = new(1); - - protected override void OnInit() - { - Score.Register(newScore => - { - if (newScore > HighScore.Value) - { - HighScore.Value = newScore; - this.SendEvent(new NewHighScoreEvent { Score = newScore }); - } - }); - } - - public override void OnArchitecturePhase(ArchitecturePhase phase) - { - switch (phase) - { - case ArchitecturePhase.ShuttingDown: - // 游戏模型清理工作 - break; - default: - break; - } - } -} -``` - -## 最佳实践 - -1. **使用 BindableProperty 存储需要监听的数据** -2. **Model 之间不要直接调用,通过 Command/System 协调** -3. **复杂计算和业务逻辑放在 System 中** -4. **使用事件通知数据的重要变化** -5. **保持 Model 简单纯粹,只做数据管理** - -## 相关包 - -- [`architecture`](../architecture/README.md) - 提供 Model 的注册和获取 -- [`property`](../property/README.md) - BindableProperty 用于定义可监听属性 -- [`events`](../events/README.md) - Model 发送事件通知变化 -- [`utility`](../utility/README.md) - Model 可以使用工具类 -- [`extensions`](../extensions/README.md) - 提供 GetModel 等扩展方法 \ No newline at end of file diff --git a/GFramework.Core/pool/README.md b/GFramework.Core/pool/README.md deleted file mode 100644 index f2f690f..0000000 --- a/GFramework.Core/pool/README.md +++ /dev/null @@ -1,951 +0,0 @@ -# 对象池系统 (Object Pool System) - -## 概述 - -GFramework 的对象池系统是一个高效的内存管理机制,旨在减少垃圾回收(GC)压力,通过复用对象实例来提高应用程序性能。该系统实现了对象的创建、获取、释放和销毁的完整生命周期管理。 - -**核心优势:** - -- **减少 GC 压力**:复用对象实例,避免频繁的内存分配和回收 -- **提高性能**:避免重复创建开销大的对象 -- **灵活管理**:支持多个独立的对象池,按需分类管理 -- **自动生命周期**:与 System 生命周期集成,自动管理对象销毁 -- **类型安全**:基于泛型实现,编译时类型检查 - -## 核心组件 - -### IPoolableObject 接口 - -定义了可池化对象的行为规范,所有需要池化的对象都必须实现此接口。 - -```csharp -public interface IPoolableObject -{ - /// - /// 当对象从池中获取时调用,用于初始化或重置对象状态 - /// - void OnAcquire(); - - /// - /// 当对象被放回池中时调用,用于清理对象状态 - /// - void OnRelease(); - - /// - /// 当对象池被销毁时调用,用于执行最终清理 - /// - void OnPoolDestroy(); -} -``` - -**生命周期:** - -``` -创建 → Acquire(从池取出)→ 使用 → Release(放回池)→ 可再次 Acquire - ↓ - Pool Destroy → OnPoolDestroy → 销毁 -``` - -### IObjectPoolSystem 接口 - -定义了对象池系统的基本操作接口。 - -```csharp -public interface IObjectPoolSystem - where TObject : IPoolableObject - where TKey : notnull -{ - /// - /// 从指定键的对象池中获取一个对象 - /// - /// 对象池的键值 - /// 获取到的对象实例 - TObject Acquire(TKey key); - - /// - /// 将对象释放回指定键的对象池中 - /// - /// 对象池的键值 - /// 需要释放的对象 - void Release(TKey key, TObject obj); - - /// - /// 清空所有对象池,销毁所有池中的对象 - /// - void Clear(); -} -``` - -### AbstractObjectPoolSystem 抽象类 - -实现了 `IObjectPoolSystem` 接口的具体逻辑,提供了对象池管理的完整实现。 - -**核心特性:** - -- 使用字典存储多个对象池,以键区分不同的对象池 -- 使用栈(Stack)存储池中的对象,实现 LIFO(后进先出)管理 -- 提供获取和释放对象的方法 -- 通过抽象方法 `Create` 让子类决定如何创建对象 -- 在系统销毁时自动清理所有对象池 - -**内部实现:** - -```csharp -public abstract class AbstractObjectPoolSystem - : AbstractSystem, IObjectPoolSystem - where TObject : IPoolableObject - where TKey : notnull -{ - // 存储对象池的字典,键为池标识,值为对应类型的对象栈 - protected readonly Dictionary> Pools = new(); - - // 获取对象 - public TObject Acquire(TKey key) - { - if (!Pools.TryGetValue(key, out var pool)) - { - pool = new Stack(); - Pools[key] = pool; - } - - var obj = pool.Count > 0 - ? pool.Pop() // 从池中取出 - : Create(key); // 创建新对象 - - obj.OnAcquire(); // 调用对象的获取钩子 - return obj; - } - - // 释放对象 - public void Release(TKey key, TObject obj) - { - obj.OnRelease(); // 调用对象的释放钩子 - - if (!Pools.TryGetValue(key, out var pool)) - { - pool = new Stack(); - Pools[key] = pool; - } - - pool.Push(obj); // 放回池中 - } - - // 清空所有对象池 - public void Clear() - { - foreach (var obj in Pools.Values.SelectMany(pool => pool)) - { - obj.OnPoolDestroy(); // 调用对象的销毁钩子 - } - - Pools.Clear(); - } - - // 子类实现:创建新对象 - protected abstract TObject Create(TKey key); - - // 系统销毁时自动清空对象池 - protected override void OnDestroy() - { - Clear(); - } -} -``` - -## 基本使用 - -### 1. 定义池化对象 - -首先,创建一个实现 `IPoolableObject` 接口的类。 - -```csharp -public class Bullet : IPoolableObject -{ - public int Damage { get; private set; } - public float Speed { get; private set; } - public Vector3 Position { get; private set; } - public Vector3 Direction { get; private set; } - public bool IsActive { get; private set; } - - public void OnAcquire() - { - // 从池中获取时调用,初始化对象状态 - IsActive = true; - } - - public void OnRelease() - { - // 放回池中时调用,清理对象状态 - IsActive = false; - Damage = 0; - Speed = 0; - Position = Vector3.Zero; - Direction = Vector3.Zero; - } - - public void OnPoolDestroy() - { - // 对象池销毁时调用,执行最终清理 - // 可以在这里释放非托管资源 - } - - // 设置子弹属性的方法 - public void Setup(int damage, float speed, Vector3 position, Vector3 direction) - { - Damage = damage; - Speed = speed; - Position = position; - Direction = direction; - } - - // 更新子弹逻辑 - public void Update(float deltaTime) - { - Position += Direction * Speed * deltaTime; - } -} -``` - -### 2. 实现对象池系统 - -继承 `AbstractObjectPoolSystem` 并实现 `Create` 方法。 - -```csharp -public class BulletPoolSystem : AbstractObjectPoolSystem -{ - protected override Bullet Create(string key) - { - // 根据键值创建不同类型的子弹 - return key switch - { - "standard" => new Bullet(), - "heavy" => new Bullet(), - "explosive" => new Bullet(), - _ => new Bullet() - }; - } - - protected override void OnInit() - { - // 可以预先创建一些对象放入池中 - for (int i = 0; i < 10; i++) - { - var bullet = Create("standard"); - bullet.OnAcquire(); - bullet.OnRelease(); - Release("standard", bullet); - } - } -} -``` - -### 3. 在架构中注册对象池系统 - -```csharp -public class GameArchitecture : Architecture -{ - protected override void Init() - { - // 注册其他组件 - RegisterModel(new PlayerModel()); - RegisterSystem(new CombatSystem()); - - // 注册对象池系统 - RegisterSystem(new BulletPoolSystem()); - } -} -``` - -### 4. 使用对象池 - -```csharp -public class ShootingSystem : AbstractSystem -{ - private BulletPoolSystem _bulletPool; - private List _activeBullets = new(); - - protected override void OnInit() - { - _bulletPool = this.GetSystem(); - this.RegisterEvent(OnShoot); - this.RegisterEvent(OnUpdate); - } - - private void OnShoot(ShootEvent e) - { - // 从对象池获取子弹 - var bullet = _bulletPool.Acquire("standard"); - - // 设置子弹属性 - bullet.Setup( - damage: e.Damage, - speed: 10.0f, - position: e.StartPosition, - direction: e.Direction - ); - - // 添加到活跃列表 - _activeBullets.Add(bullet); - } - - private void OnUpdate(GameUpdateEvent e) - { - // 更新所有活跃子弹 - for (int i = _activeBullets.Count - 1; i >= 0; i--) - { - var bullet = _activeBullets[i]; - bullet.Update(e.DeltaTime); - - // 检查子弹是否需要销毁(例如:超出范围或击中目标) - if (ShouldDestroyBullet(bullet)) - { - // 放回对象池 - _bulletPool.Release("standard", bullet); - _activeBullets.RemoveAt(i); - } - } - } - - private bool ShouldDestroyBullet(Bullet bullet) - { - // 简单示例:子弹超出一定范围则销毁 - return bullet.Position.Length() > 1000.0f; - } -} -``` - -## 高级用法 - -### 1. 多键对象池管理 - -```csharp -public class ParticlePoolSystem : AbstractObjectPoolSystem -{ - protected override Particle Create(string key) - { - // 根据键值创建不同类型的粒子效果 - return key switch - { - "explosion" => new Particle(explosionPrefab), - "smoke" => new Particle(smokePrefab), - "spark" => new Particle(sparkPrefab), - _ => throw new ArgumentException($"Unknown particle type: {key}") - }; - } - - // 提供便捷方法 - public Particle SpawnExplosion(Vector3 position) - { - var particle = Acquire("explosion"); - particle.Position = position; - particle.Play(); - return particle; - } -} - -// 使用 -public class EffectSystem : AbstractSystem -{ - private ParticlePoolSystem _particlePool; - - protected override void OnInit() - { - _particlePool = this.GetSystem(); - } - - public void PlayExplosion(Vector3 position) - { - _particlePool.SpawnExplosion(position); - } -} -``` - -### 2. 动态对象池管理 - -```csharp -public class EnemyPoolSystem : AbstractObjectPoolSystem -{ - protected override Enemy Create(string key) - { - // 根据敌人类型创建不同的敌人 - var enemyPrefab = LoadEnemyPrefab(key); - return new Enemy(enemyPrefab); - } - - // 动态注册新的敌人类型池 - public void RegisterEnemyType(string enemyType) - { - if (!Pools.ContainsKey(enemyType)) - { - Pools[enemyType] = new Stack(); - - // 预热:预先创建几个敌人放入池中 - for (int i = 0; i < 3; i++) - { - var enemy = Create(enemyType); - enemy.OnAcquire(); - enemy.OnRelease(); - Release(enemyType, enemy); - } - } - } -} - -// 使用 -public class EnemySpawnerSystem : AbstractSystem -{ - private EnemyPoolSystem _enemyPool; - - protected override void OnInit() - { - _enemyPool = this.GetSystem(); - - // 注册不同类型的敌人 - _enemyPool.RegisterEnemyType("goblin"); - _enemyPool.RegisterEnemyType("orc"); - _enemyPool.RegisterEnemyType("dragon"); - } - - public void SpawnEnemy(string enemyType, Vector3 position) - { - var enemy = _enemyPool.Acquire(enemyType); - enemy.Position = position; - enemy.Activate(); - } -} -``` - -### 3. 对象池大小限制 - -```csharp -public class LimitedBulletPoolSystem : AbstractObjectPoolSystem -{ - private const int MaxPoolSize = 50; - - protected override Bullet Create(string key) - { - return new Bullet(); - } - - public new void Release(string key, Bullet obj) - { - // 检查对象池大小 - if (Pools.TryGetValue(key, out var pool) && pool.Count >= MaxPoolSize) - { - // 池已满,不回收对象,让它被 GC 回收 - return; - } - - // 调用基类的 Release 方法 - base.Release(key, obj); - } -} -``` - -### 4. 对象池统计和调试 - -```csharp -public class DebuggablePoolSystem : AbstractObjectPoolSystem -{ - public Dictionary PoolSizes => Pools.ToDictionary( - kvp => kvp.Key, - kvp => kvp.Value.Count - ); - - public int TotalPooledObjects => Pools.Values.Sum(stack => stack.Count); - - public void LogPoolStatus() - { - foreach (var (key, stack) in Pools) - { - Console.WriteLine($"Pool [{key}]: {stack.Count} objects"); - } - - Console.WriteLine($"Total pooled objects: {TotalPooledObjects}"); - } - - protected override void OnDestroy() - { - LogPoolStatus(); - base.OnDestroy(); - } -} -``` - -## 使用场景 - -### 1. 游戏对象池 - -**适用对象:** - -- 子弹、箭矢、投射物 -- 敌人、NPC -- 爆炸效果、粒子系统 -- UI 元素(提示、对话框) - -**示例:子弹池** - -```csharp -// 定义子弹 -public class Bullet : IPoolableObject -{ - public Vector3 Position { get; private set; } - public Vector3 Velocity { get; private set; } - public float Lifetime { get; private set; } - - public void OnAcquire() - { - Lifetime = 5.0f; // 5秒后自动销毁 - } - - public void OnRelease() - { - Position = Vector3.Zero; - Velocity = Vector3.Zero; - } - - public void OnPoolDestroy() { } - - public void Update(float deltaTime) - { - Position += Velocity * deltaTime; - Lifetime -= deltaTime; - } -} - -// 子弹对象池 -public class BulletPoolSystem : AbstractObjectPoolSystem -{ - protected override Bullet Create(string key) => new Bullet(); -} - -// 射击系统 -public class ShootingSystem : AbstractSystem -{ - private BulletPoolSystem _bulletPool; - private List _activeBullets = new(); - - protected override void OnInit() - { - _bulletPool = this.GetSystem(); - this.RegisterEvent(OnShoot); - this.RegisterEvent(OnUpdate); - } - - private void OnShoot(ShootEvent e) - { - var bullet = _bulletPool.Acquire("normal"); - bullet.Position = e.StartPosition; - bullet.Velocity = e.Direction * e.Speed; - _activeBullets.Add(bullet); - } - - private void OnUpdate(GameUpdateEvent e) - { - for (int i = _activeBullets.Count - 1; i >= 0; i--) - { - var bullet = _activeBullets[i]; - bullet.Update(e.DeltaTime); - - if (bullet.Lifetime <= 0) - { - _bulletPool.Release("normal", bullet); - _activeBullets.RemoveAt(i); - } - } - } -} -``` - -### 2. UI 元素池 - -**适用对象:** - -- 对话框 -- 提示框 -- 菜单项 -- 列表项 - -**示例:提示框池** - -```csharp -public class Tooltip : IPoolableObject -{ - public string Text { get; set; } - public bool IsActive { get; private set; } - - public void OnAcquire() - { - IsActive = true; - } - - public void OnRelease() - { - IsActive = false; - Text = ""; - } - - public void OnPoolDestroy() { } - - public void Show(string text, Vector3 position) - { - Text = text; - // 更新 UI 位置和内容 - } -} - -public class TooltipPoolSystem : AbstractObjectPoolSystem -{ - protected override Tooltip Create(string key) => new Tooltip(); -} - -public class UISystem : AbstractSystem -{ - private TooltipPoolSystem _tooltipPool; - - protected override void OnInit() - { - _tooltipPool = this.GetSystem(); - } - - public void ShowTooltip(string text, Vector3 position) - { - var tooltip = _tooltipPool.Acquire("default"); - tooltip.Show(text, position); - } -} -``` - -### 3. 网络消息对象池 - -**适用对象:** - -- 网络包 -- 协议消息 -- 数据包 - -**示例:网络包池** - -```csharp -public class NetworkPacket : IPoolableObject -{ - public byte[] Data { get; private set; } - public int Length { get; private set; } - - public void OnAcquire() - { - Data = Array.Empty(); - Length = 0; - } - - public void OnRelease() - { - // 清理敏感数据 - if (Data != null) - { - Array.Clear(Data, 0, Data.Length); - } - Length = 0; - } - - public void OnPoolDestroy() { } - - public void SetData(byte[] data) - { - Data = data; - Length = data.Length; - } -} - -public class PacketPoolSystem : AbstractObjectPoolSystem -{ - protected override NetworkPacket Create(string key) => new NetworkPacket(); -} -``` - -## 最佳实践 - -### 1. 对象生命周期管理 - -```csharp -// ✅ 好的做法:确保所有对象都放回池中 -public class BulletSystem : AbstractSystem -{ - private List _activeBullets = new(); - - protected override void OnDestroy() - { - // 系统销毁时,确保所有活跃子弹都放回池中 - foreach (var bullet in _activeBullets) - { - _bulletPool.Release("standard", bullet); - } - - _activeBullets.Clear(); - base.OnDestroy(); - } -} - -// ❌ 不好的做法:忘记放回对象,导致泄漏 -public class BadBulletSystem : AbstractSystem -{ - private List _activeBullets = new(); - - private void OnUpdate(GameUpdateEvent e) - { - // 子弹销毁时忘记放回池中 - if (bullet.Lifetime <= 0) - { - _activeBullets.RemoveAt(i); - // 忘记调用 _bulletPool.Release(...) - } - } -} -``` - -### 2. 对象状态重置 - -```csharp -// ✅ 好的做法:在 OnRelease 中彻底重置对象状态 -public class Bullet : IPoolableObject -{ - public int Damage { get; set; } - public float Speed { get; set; } - public List Tags { get; set; } - public Dictionary Data { get; set; } - - public void OnRelease() - { - // 重置所有属性 - Damage = 0; - Speed = 0; - Tags?.Clear(); - Data?.Clear(); - - // 也可以设置为新实例(如果性能允许) - Tags = new List(); - Data = new Dictionary(); - } -} - -// ❌ 不好的做法:不完全重置状态 -public class BadBullet : IPoolableObject -{ - public List Tags = new List(); - - public void OnRelease() - { - // 只清空列表,但列表实例本身保留 - // 这可能导致问题:如果其他代码持有列表引用 - Tags.Clear(); - } -} -``` - -### 3. 对象池预热 - -```csharp -// ✅ 好的做法:预先创建一些对象放入池中 -public class BulletPoolSystem : AbstractObjectPoolSystem -{ - protected override Bullet Create(string key) => new Bullet(); - - protected override void OnInit() - { - // 为常用的子弹类型预热对象池 - var commonTypes = new[] { "standard", "heavy", "sniper" }; - - foreach (var type in commonTypes) - { - // 预先创建 5 个对象 - for (int i = 0; i < 5; i++) - { - var bullet = Create(type); - bullet.OnAcquire(); - bullet.OnRelease(); - Release(type, bullet); - } - } - } -} -``` - -### 4. 对象池大小管理 - -```csharp -// ✅ 好的做法:限制对象池大小,避免内存浪费 -public class BoundedPoolSystem : AbstractObjectPoolSystem -{ - private const int MaxPoolSize = 100; - - public new void Release(string key, PooledObject obj) - { - if (Pools.TryGetValue(key, out var pool) && pool.Count >= MaxPoolSize) - { - // 池已满,不回收对象 - return; - } - - base.Release(key, obj); - } -} - -// ✅ 好的做法:动态调整对象池大小 -public class AdaptivePoolSystem : AbstractObjectPoolSystem -{ - private Dictionary _peakUsage = new(); - - public new void Release(string key, PooledObject obj) - { - // 记录峰值使用量 - if (Pools.TryGetValue(key, out var pool)) - { - _peakUsage[key] = Math.Max(_peakUsage.GetValueOrDefault(key, 0), pool.Count); - } - - // 根据使用情况动态调整 - int maxAllowed = _peakUsage.GetValueOrDefault(key, 10) * 2; - if (pool.Count >= maxAllowed) - { - return; // 不回收 - } - - base.Release(key, obj); - } -} -``` - -### 5. 调试和监控 - -```csharp -// ✅ 好的做法:添加对象池统计功能 -public class MonitoredPoolSystem : AbstractObjectPoolSystem -{ - private Dictionary _acquireCount = new(); - private Dictionary _releaseCount = new(); - - public new PooledObject Acquire(string key) - { - _acquireCount[key] = _acquireCount.GetValueOrDefault(key, 0) + 1; - return base.Acquire(key); - } - - public new void Release(string key, PooledObject obj) - { - _releaseCount[key] = _releaseCount.GetValueOrDefault(key, 0) + 1; - base.Release(key, obj); - } - - public void PrintStatistics() - { - foreach (var key in Pools.Keys) - { - int acquired = _acquireCount.GetValueOrDefault(key, 0); - int released = _releaseCount.GetValueOrDefault(key, 0); - int leaked = acquired - released; - - Console.WriteLine($"Pool [{key}]:"); - Console.WriteLine($" Acquired: {acquired}"); - Console.WriteLine($" Released: {released}"); - Console.WriteLine($" Leaked: {leaked}"); - Console.WriteLine($" Pool size: {Pools[key].Count}"); - } - } -} -``` - -## 性能优化 - -### 1. 减少对象创建 - -```csharp -// ✅ 好的做法:对象池预热,避免运行时创建 -public class PreheatedPoolSystem : AbstractObjectPoolSystem -{ - protected override Bullet Create(string key) => new Bullet(); - - protected override void OnInit() - { - // 预热常用对象池 - PreheatPool("standard", 20); - PreheatPool("heavy", 10); - } - - private void PreheatPool(string key, int count) - { - for (int i = 0; i < count; i++) - { - var bullet = Create(key); - bullet.OnAcquire(); - bullet.OnRelease(); - Release(key, bullet); - } - } -} -``` - -### 2. 使用值类型作为键 - -```csharp -// ✅ 好的做法:使用枚举或整数作为键,避免字符串比较 -public enum BulletType -{ - Standard, - Heavy, - Explosive -} - -public class FastBulletPoolSystem : AbstractObjectPoolSystem -{ - protected override Bullet Create(BulletType key) => key switch - { - BulletType.Standard => new Bullet(), - BulletType.Heavy => new Bullet(), - BulletType.Explosive => new Bullet(), - _ => throw new ArgumentException() - }; -} -``` - -### 3. 批量操作 - -```csharp -// ✅ 好的做法:批量获取和释放对象 -public class BatchPoolSystem : AbstractObjectPoolSystem -{ - public List AcquireBatch(string key, int count) - { - var objects = new List(count); - for (int i = 0; i < count; i++) - { - objects.Add(Acquire(key)); - } - return objects; - } - - public void ReleaseBatch(string key, IEnumerable objects) - { - foreach (var obj in objects) - { - Release(key, obj); - } - } -} -``` - -## 注意事项 - -1. **对象状态管理**:确保 `OnRelease` 方法彻底重置对象状态,避免状态污染 -2. **对象引用**:不要在放回对象池后继续持有对象引用 -3. **线程安全**:对象池本身不是线程安全的,如需多线程访问,需要自行加锁 -4. **内存泄漏**:确保所有获取的对象最终都放回池中 -5. **对象池大小**:合理设置对象池大小,避免内存浪费或频繁创建 - -## 相关包 - -- [`system`](../system/README.md) - 对象池系统继承自 AbstractSystem -- [`architecture`](../architecture/README.md) - 在架构中注册对象池系统 - ---- - -**许可证**: Apache 2.0 diff --git a/GFramework.Core/property/README.md b/GFramework.Core/property/README.md deleted file mode 100644 index 2f89907..0000000 --- a/GFramework.Core/property/README.md +++ /dev/null @@ -1,341 +0,0 @@ -# Property 包使用说明 - -## 概述 - -Property 包提供了可绑定属性(BindableProperty)的实现,支持属性值的监听和响应式编程。这是实现数据绑定和响应式编程的核心组件。 - -## 核心接口 - -### [`IReadonlyBindableProperty`](IReadonlyBindableProperty.cs) - -只读可绑定属性接口,提供属性值的读取和变更监听功能。 - -**核心成员:** - -```csharp -// 获取属性值 -T Value { get; } - -// 注册监听(不立即触发回调) -IUnRegister Register(Action onValueChanged); - -// 注册监听并立即触发回调传递当前值 -IUnRegister RegisterWithInitValue(Action action); - -// 取消监听 -void UnRegister(Action onValueChanged); -``` - -### [`IBindableProperty`](IBindableProperty.cs) - -可绑定属性接口,继承自只读接口,增加了修改能力。 - -**核心成员:** - -```csharp -// 可读写的属性值 -new T Value { get; set; } - -// 设置值但不触发事件 -void SetValueWithoutEvent(T newValue); -``` - -## 核心类 - -### [`BindableProperty`](BindableProperty.cs) - -可绑定属性的完整实现。 - -**使用示例:** - -```csharp -// 创建可绑定属性 -var health = new BindableProperty(100); - -// 监听值变化(不会立即触发) -var unregister = health.Register(newValue => -{ - GD.Print($"Health changed to: {newValue}"); -}); - -// 设置值(会触发监听器) -health.Value = 50; // 输出: Health changed to: 50 - -// 取消监听 -unregister.UnRegister(); - -// 设置值但不触发事件 -health.SetValueWithoutEvent(75); -``` - -**高级功能:** - -```csharp -// 1. 注册并立即获得当前值 -health.RegisterWithInitValue(value => -{ - GD.Print($"Current health: {value}"); // 立即输出当前值 - // 后续值变化时也会调用 -}); - -// 2. 自定义比较器(静态方法) -BindableProperty.Comparer = (a, b) => Math.Abs(a - b) < 1; - -// 3. 使用实例方法设置比较器 -var position = new BindableProperty(Vector3.Zero) - .WithComparer((a, b) => a.DistanceTo(b) < 0.01f); // 距离小于0.01认为相等 -``` - -### [`BindablePropertyUnRegister`](BindablePropertyUnRegister.cs) - -可绑定属性的注销器,负责清理监听。 - -**使用示例:** - -```csharp -var unregister = health.Register(OnHealthChanged); -// 当需要取消监听时 -unregister.UnRegister(); -``` - -## 在 Model 中使用 - -### 定义可绑定属性 - -```csharp -public class PlayerModel : AbstractModel -{ - // 可读写属性 - public BindableProperty Name { get; } = new("Player"); - public BindableProperty Level { get; } = new(1); - public BindableProperty Health { get; } = new(100); - public BindableProperty MaxHealth { get; } = new(100); - - // 只读属性(外部只能读取和监听) - public IReadonlyBindableProperty ReadonlyHealth => Health; - - protected override void OnInit() - { - // 内部监听属性变化 - Health.Register(hp => - { - if (hp <= 0) - { - this.SendEvent(new PlayerDiedEvent()); - } - }); - } -} -``` - -## 在 Controller 中监听 - -### UI 数据绑定 - -```csharp -public partial class PlayerUI : Control, IController -{ - [Export] private Label _healthLabel; - [Export] private Label _nameLabel; - - private IUnRegisterList _unregisterList = new UnRegisterList(); - - public IArchitecture GetArchitecture() => GameArchitecture.Interface; - - public override void _Ready() - { - var playerModel = this.GetModel(); - - // 绑定生命值到UI(立即显示当前值) - playerModel.Health - .RegisterWithInitValue(health => - { - _healthLabel.Text = $"HP: {health}/{playerModel.MaxHealth.Value}"; - }) - .AddToUnregisterList(_unregisterList); - - // 绑定名称 - playerModel.Name - .RegisterWithInitValue(name => - { - _nameLabel.Text = name; - }) - .AddToUnregisterList(_unregisterList); - } - - public override void _ExitTree() - { - _unregisterList.UnRegisterAll(); - } -} -``` - -## 常见使用模式 - -### 1. 双向绑定 - -```csharp -// Model -public class SettingsModel : AbstractModel -{ - public BindableProperty MasterVolume { get; } = new(1.0f); - protected override void OnInit() { } -} - -// UI Controller -public partial class VolumeSlider : HSlider, IController -{ - private BindableProperty _volumeProperty; - - public override void _Ready() - { - _volumeProperty = this.GetModel().MasterVolume; - - // Model -> UI - _volumeProperty.RegisterWithInitValue(vol => Value = vol) - .UnRegisterWhenNodeExitTree(this); - - // UI -> Model - ValueChanged += newValue => _volumeProperty.Value = (float)newValue; - } -} -``` - -### 2. 计算属性 - -```csharp -public class PlayerModel : AbstractModel -{ - public BindableProperty Health { get; } = new(100); - public BindableProperty MaxHealth { get; } = new(100); - public BindableProperty HealthPercent { get; } = new(1.0f); - - protected override void OnInit() - { - // 自动计算百分比 - Action updatePercent = () => - { - HealthPercent.Value = (float)Health.Value / MaxHealth.Value; - }; - - Health.Register(_ => updatePercent()); - MaxHealth.Register(_ => updatePercent()); - - updatePercent(); // 初始计算 - } -} -``` - -### 3. 属性验证 - -```csharp -public class PlayerModel : AbstractModel -{ - private BindableProperty _health = new(100); - - public BindableProperty Health - { - get => _health; - set - { - // 限制范围 - var clampedValue = Math.Clamp(value.Value, 0, MaxHealth.Value); - _health.Value = clampedValue; - } - } - - public BindableProperty MaxHealth { get; } = new(100); - - protected override void OnInit() { } -} -``` - -### 4. 条件监听 - -```csharp -public class CombatController : Node, IController -{ - public override void _Ready() - { - var playerModel = this.GetModel(); - - // 只在生命值低于30%时显示警告 - playerModel.Health.Register(hp => - { - if (hp < playerModel.MaxHealth.Value * 0.3f) - { - ShowLowHealthWarning(); - } - else - { - HideLowHealthWarning(); - } - }).UnRegisterWhenNodeExitTree(this); - } -} -``` - -## 性能优化 - -### 1. 避免频繁触发 - -```csharp -// 使用 SetValueWithoutEvent 批量修改 -public void LoadPlayerData(SaveData data) -{ - // 临时关闭事件 - Health.SetValueWithoutEvent(data.Health); - Mana.SetValueWithoutEvent(data.Mana); - Gold.SetValueWithoutEvent(data.Gold); - - // 最后统一触发一次更新事件 - this.SendEvent(new PlayerDataLoadedEvent()); -} -``` - -### 2. 自定义比较器 - -```csharp -// 避免浮点数精度问题导致的频繁触发 -var position = new BindableProperty() - .WithComparer((a, b) => a.DistanceTo(b) < 0.001f); -``` - -## 实现原理 - -### 值变化检测 - -```csharp -// 使用 EqualityComparer.Default 进行比较 -if (!EqualityComparer.Default.Equals(value, MValue)) -{ - MValue = value; - _mOnValueChanged?.Invoke(value); -} -``` - -### 事件触发机制 - -```csharp -// 当值变化时触发所有注册的回调 -_mOnValueChanged?.Invoke(value); -``` - -## 最佳实践 - -1. **在 Model 中定义属性** - BindableProperty 主要用于 Model 层 -2. **使用只读接口暴露** - 防止外部随意修改 -3. **及时注销监听** - 使用 UnRegisterList 或 UnRegisterWhenNodeExitTree -4. **使用 RegisterWithInitValue** - UI 绑定时立即获取初始值 -5. **避免循环依赖** - 属性监听器中修改其他属性要小心 -6. **使用自定义比较器** - 对于浮点数等需要精度控制的属性 - -## 相关包 - -- [`model`](../model/README.md) - Model 中大量使用 BindableProperty -- [`events`](../events/README.md) - BindableProperty 基于事件系统实现 -- [`extensions`](../extensions/README.md) - 提供便捷的注销扩展方法 - ---- - -**许可证**: Apache 2.0 diff --git a/GFramework.Core/query/README.md b/GFramework.Core/query/README.md deleted file mode 100644 index e8947c3..0000000 --- a/GFramework.Core/query/README.md +++ /dev/null @@ -1,447 +0,0 @@ -# Query 包使用说明 - -## 概述 - -Query 包实现了 CQRS(命令查询职责分离)模式中的查询部分。Query 用于封装数据查询逻辑,与 Command 不同的是,Query -有返回值且不应该修改系统状态。 - -## 核心接口 - -### IQuery - -查询接口,定义了查询的基本契约。 - -**核心成员:** - -```csharp -TResult Do(); // 执行查询并返回结果 -``` - -## 核心类 - -### [`AbstractQuery`](AbstractQuery.cs) - -抽象查询基类,提供了查询的基础实现。它接受一个泛型输入参数 TInput,该参数必须实现 IQueryInput 接口。 - -**使用方式:** - -```csharp -public abstract class AbstractQuery(TInput input) : ContextAwareBase, IQuery - where TInput : IQueryInput -{ - public TResult Do() => OnDo(input); // 执行查询,传入输入参数 - protected abstract TResult OnDo(TInput input); // 子类实现查询逻辑 -} -``` - -### [`EmptyQueryInput`](EmptyQueryInput.cs) - -空查询输入类,用于表示不需要任何输入参数的查询操作。 - -**使用方式:** - -```csharp -public sealed class EmptyQueryInput : IQueryInput -{ - // 作为占位符使用,适用于那些不需要额外输入参数的查询场景 -} -``` - -### [`QueryBus`](QueryBus.cs) - -查询总线实现,负责执行查询并返回结果。 - -**使用方式:** - -```csharp -public sealed class QueryBus : IQueryBus -{ - public TResult Send(IQuery query) - { - ArgumentNullException.ThrowIfNull(query); - return query.Do(); - } -} -``` - -## 基本使用 - -### 1. 定义查询 - -``csharp -// 定义查询输入参数 -public record GetPlayerGoldQueryInput : IQueryInput; - -// 查询玩家金币数量 -public class GetPlayerGoldQuery : AbstractQuery -{ -public GetPlayerGoldQuery() : base(new EmptyQueryInput()) -{ -} - - protected override int OnDo(GetPlayerGoldQueryInput input) - { - return this.GetModel().Gold.Value; - } - -} - -// 查询玩家是否死亡 -public record IsPlayerDeadQueryInput : IQueryInput; - -public class IsPlayerDeadQuery : AbstractQuery -{ -public IsPlayerDeadQuery() : base(new EmptyQueryInput()) -{ -} - - protected override bool OnDo(IsPlayerDeadQueryInput input) - { - return this.GetModel().Health.Value <= 0; - } - -} - -// 查询背包中指定物品的数量 -public record GetItemCountQueryInput(string ItemId) : IQueryInput; - -public class GetItemCountQuery : AbstractQuery -{ -public GetItemCountQuery(string itemId) : base(new GetItemCountQueryInput(itemId)) -{ -} - - protected override int OnDo(GetItemCountQueryInput input) - { - var inventory = this.GetModel(); - return inventory.GetItemCount(input.ItemId); - } - -} - -``` - -### 2. 发送查询(在 Controller 中) - -``csharp -public partial class ShopUI : Control, IController -{ - [Export] private Button _buyButton; - [Export] private int _itemPrice = 100; - - public IArchitecture GetArchitecture() => GameArchitecture.Interface; - - public override void _Ready() - { - _buyButton.Pressed += OnBuyButtonPressed; - } - - private void OnBuyButtonPressed() - { - // 查询玩家金币 - int playerGold = this.SendQuery(new GetPlayerGoldQuery()); - - if (playerGold >= _itemPrice) - { - // 发送购买命令 - this.SendCommand(new BuyItemCommand { ItemId = "sword_01" }); - } - else - { - GD.Print("金币不足!"); - } - } -} -``` - -### 3. 在 System 中使用 - -``csharp -public class CombatSystem : AbstractSystem -{ -protected override void OnInit() -{ -// 注册事件监听 -this.RegisterEvent(OnEnemyAttack); -} - - private void OnEnemyAttack(EnemyAttackEvent e) - { - // 查询玩家是否已经死亡 - bool isDead = this.SendQuery(new IsPlayerDeadQuery()); - - if (!isDead) - { - // 执行伤害逻辑 - this.SendCommand(new TakeDamageCommand { Damage = e.Damage }); - } - } - -} - -``` - -## 高级用法 - -### 1. 带参数的复杂查询 - -``csharp -// 查询指定范围内的敌人列表 -public class GetEnemiesInRangeQuery : AbstractQuery> -{ - public Vector3 Center { get; set; } - public float Radius { get; set; } - - protected override List OnDo() - { - var enemySystem = this.GetSystem(); - return enemySystem.GetEnemiesInRange(Center, Radius); - } -} - -// 使用 -var enemies = this.SendQuery(new GetEnemiesInRangeQuery -{ - Center = playerPosition, - Radius = 10.0f -}); -``` - -### 2. 组合查询 - -``csharp -// 查询玩家是否可以使用技能 -public class CanUseSkillQuery : AbstractQuery -{ -public string SkillId { get; set; } - - protected override bool OnDo() - { - var playerModel = this.GetModel(); - var skillModel = this.GetModel(); - - // 查询技能消耗 - var skillCost = this.SendQuery(new GetSkillCostQuery { SkillId = SkillId }); - - // 检查是否满足条件 - return playerModel.Mana.Value >= skillCost.ManaCost - && !this.SendQuery(new IsSkillOnCooldownQuery { SkillId = SkillId }); - } - -} - -public class GetSkillCostQuery : AbstractQuery -{ -public string SkillId { get; set; } - - protected override SkillCost OnDo() - { - return this.GetModel().GetSkillCost(SkillId); - } - -} - -public class IsSkillOnCooldownQuery : AbstractQuery -{ -public string SkillId { get; set; } - - protected override bool OnDo() - { - return this.GetModel().IsOnCooldown(SkillId); - } - -} - -``` - -### 3. 聚合数据查询 - -``csharp -// 查询玩家战斗力 -public class GetPlayerPowerQuery : AbstractQuery -{ - protected override int OnDo() - { - var playerModel = this.GetModel(); - var equipmentModel = this.GetModel(); - - int basePower = playerModel.Level.Value * 10; - int equipmentPower = equipmentModel.GetTotalPower(); - int buffPower = this.SendQuery(new GetBuffPowerQuery()); - - return basePower + equipmentPower + buffPower; - } -} - -// 查询玩家详细信息(用于UI显示) -public class GetPlayerInfoQuery : AbstractQuery -{ - protected override PlayerInfo OnDo() - { - var playerModel = this.GetModel(); - - return new PlayerInfo - { - Name = playerModel.Name.Value, - Level = playerModel.Level.Value, - Health = playerModel.Health.Value, - MaxHealth = playerModel.MaxHealth.Value, - Gold = this.SendQuery(new GetPlayerGoldQuery()), - Power = this.SendQuery(new GetPlayerPowerQuery()) - }; - } -} -``` - -### 4. 跨 System 查询 - -``csharp -// 在 AI System 中查询玩家状态 -public class EnemyAISystem : AbstractSystem -{ -protected override void OnInit() { } - - public void UpdateEnemyBehavior(Enemy enemy) - { - // 查询玩家位置 - var playerPos = this.SendQuery(new GetPlayerPositionQuery()); - - // 查询玩家是否在攻击范围内 - bool inRange = this.SendQuery(new IsPlayerInRangeQuery - { - Position = enemy.Position, - Range = enemy.AttackRange - }); - - if (inRange) - { - // 查询是否可以攻击 - bool canAttack = this.SendQuery(new CanEnemyAttackQuery - { - EnemyId = enemy.Id - }); - - if (canAttack) - { - this.SendCommand(new EnemyAttackCommand { EnemyId = enemy.Id }); - } - } - } - -} - -``` - -## Command vs Query - -### Command(命令) - -- **用途**:修改系统状态 -- **返回值**:无返回值(void) -- **示例**:购买物品、造成伤害、升级角色 - -### Query(查询) - -- **用途**:读取数据,不修改状态 -- **返回值**:有返回值 -- **示例**:获取金币数量、检查技能冷却、查询玩家位置 - -``csharp -// ❌ 错误:在 Query 中修改状态 -public class BadQuery : AbstractQuery -{ - protected override int OnDo() - { - var model = this.GetModel(); - model.Gold.Value += 100; // 不应该在 Query 中修改数据! - return model.Gold.Value; - } -} - -// ✅ 正确:Query 只读取数据 -public class GoodQuery : AbstractQuery -{ - protected override int OnDo() - { - return this.GetModel().Gold.Value; - } -} - -// ✅ 修改数据应该使用 Command -public class AddGoldCommand : AbstractCommand -{ - public int Amount { get; set; } - - protected override void OnExecute() - { - var model = this.GetModel(); - model.Gold.Value += Amount; - } -} -``` - -## 最佳实践 - -1. **查询只读取,不修改** - 保持 Query 的纯粹性 -2. **小而专注** - 每个 Query 只负责一个具体的查询任务 -3. **可组合** - 复杂查询可以通过组合简单查询实现 -4. **避免过度查询** - 如果需要频繁查询,考虑使用 BindableProperty -5. **命名清晰** - Query 名称应该清楚表达查询意图(Get、Is、Can、Has等前缀) - -## 性能优化 - -### 1. 缓存查询结果 - -``csharp -// 在 Model 中缓存复杂计算 -public class PlayerModel : AbstractModel -{ -private int? _cachedPower; - - public int GetPower() - { - if (_cachedPower == null) - { - _cachedPower = CalculatePower(); - } - return _cachedPower.Value; - } - - private int CalculatePower() - { - // 复杂计算... - return 100; - } - - public void InvalidatePowerCache() - { - _cachedPower = null; - } - -} - -``` - -### 2. 批量查询 - -``csharp -// 一次查询多个数据,而不是多次单独查询 -public class GetMultipleItemCountsQuery : AbstractQuery> -{ - public List ItemIds { get; set; } - - protected override Dictionary OnDo() - { - var inventory = this.GetModel(); - return ItemIds.ToDictionary(id => id, id => inventory.GetItemCount(id)); - } -} -``` - -## 相关包 - -- [`command`](../command/README.md) - CQRS 的命令部分 -- [`model`](../model/README.md) - Query 主要从 Model 获取数据 -- [`system`](../system/README.md) - System 中可以发送 Query -- [`controller`](../controller/README.md) - Controller 中可以发送 Query -- [`extensions`](../extensions/README.md) - 提供 SendQuery 扩展方法 \ No newline at end of file diff --git a/GFramework.Core/rule/README.md b/GFramework.Core/rule/README.md deleted file mode 100644 index 6614df3..0000000 --- a/GFramework.Core/rule/README.md +++ /dev/null @@ -1,316 +0,0 @@ -# Rule 包使用说明 - -## 概述 - -Rule 包定义了框架的核心规则接口,这些接口规定了框架各个组件之间的关系和约束。所有框架组件都需要遵循这些规则接口。 - -## 核心接口 - -### IContextAware - -标记接口,表示该类型可以感知架构上下文。 - -**接口定义:** - -```csharp -public interface IContextAware -{ - void SetContext(IArchitectureContext context); - IArchitectureContext GetContext(); -} -``` - -**实现此接口的类型:** - -- System -- Query -- Model -- Command -- 以及其他需要感知架构上下文的组件 - -**作用:** -所有实现此接口的类型都能够获取其所属的架构上下文实例,从而访问架构提供的各种能力。 - -## 核心类 - -### [`ContextAwareBase`](ContextAwareBase.cs) - -上下文感知基类,实现了 IContextAware 接口,为需要感知架构上下文的类提供基础实现。 - -**使用方式:** - -```csharp -public abstract class ContextAwareBase : IContextAware -{ - protected IArchitectureContext? Context { get; set; } - - void IContextAware.SetContext(IArchitectureContext context) - { - Context = context; - OnContextReady(); // 上下文准备好后调用此方法 - } - - IArchitectureContext IContextAware.GetContext() - { - Context ??= GameContext.GetFirstArchitectureContext(); - return Context; - } - - protected virtual void OnContextReady() // 子类可以重写此方法进行初始化 - { - } -} -``` - -## 接口关系图 - -``` -IContextAware (上下文感知接口) - ↓ 被继承于 - ├── AbstractSystem (抽象系统基类) - ├── AbstractQuery (抽象查询基类) - ├── AbstractModel (抽象模型基类) - └── AbstractCommand (抽象命令基类) -``` - -## 使用场景 - -### 1. Component 继承 ContextAwareBase - -```csharp -// 组件通过继承 ContextAwareBase 获得架构上下文访问能力 -public partial class PlayerController : Node, IController -{ - // 不再需要手动实现 IContextAware,基类已处理 - // 可以直接使用扩展方法 - public override void _Ready() - { - var playerModel = this.GetModel(); - this.SendCommand(new InitPlayerCommand()); - this.RegisterEvent(OnPlayerDied); - } - - private void OnPlayerDied(PlayerDiedEvent e) - { - GD.Print("Player died!"); - } -} -``` - -### 2. Command 继承 AbstractCommand (IContextAware) - -```csharp -// Command 继承 AbstractCommand,自动成为 IContextAware -public class BuyItemCommand : AbstractCommand -{ - public string ItemId { get; set; } - - protected override void OnExecute() - { - // 框架或上下文系统会自动注入 IArchitectureContext - // 所以这里可以直接使用 this.GetModel - var playerModel = this.GetModel(); - var shopModel = this.GetModel(); - - int price = shopModel.GetItemPrice(ItemId); - if (playerModel.Gold.Value >= price) - { - playerModel.Gold.Value -= price; - this.SendCommand(new AddItemCommand { ItemId = ItemId }); - } - } -} -``` - -### 3. 自定义组件遵循规则 - -```csharp -// 自定义管理器遵循框架规则,继承 ContextAwareBase -public class SaveManager : ContextAwareBase -{ - // 不再需要手动构造函数传参,上下文由框架注入 - // protected override void OnContextReady() 可用于初始化 - - public void SaveGame() - { - // 因为继承了 ContextAwareBase,可以使用扩展方法 - var playerModel = this.GetModel(); - var saveData = new SaveData - { - PlayerName = playerModel.Name.Value, - Level = playerModel.Level.Value, - Gold = playerModel.Gold.Value - }; - - // 保存逻辑... - } -} -``` - -## 规则约束 - -### 1. 组件注册规则 - -```csharp -public class GameArchitecture : Architecture -{ - protected override void Init() - { - // Model/System/Utility 自动获得架构引用 - this.RegisterModel(new PlayerModel()); - this.RegisterSystem(new CombatSystem()); - this.RegisterUtility(new StorageUtility()); - } -} -``` - -### 2. Command/Query 自动注入规则 - -```csharp -// Controller 中发送 Command -public class ShopUI : Control, IController -{ - public IArchitecture GetArchitecture() => GameArchitecture.Interface; - - private void OnBuyButtonPressed() - { - var command = new BuyItemCommand { ItemId = "sword_01" }; - - // SendCommand 内部会自动调用 command.SetArchitecture(this.GetArchitecture()) - this.SendCommand(command); - } -} - -// Command 执行时已经有了架构引用 -public class BuyItemCommand : AbstractCommand -{ - public string ItemId { get; set; } - - protected override void OnExecute() - { - // 此时 GetArchitecture() 已经可用 - var model = this.GetModel(); - } -} -``` - -## 设计模式 - -### 1. 依赖注入模式 - -Rule 接口体现了依赖注入(DI)的思想: - -```csharp -// 接口定义了"需要什么" -public interface IContextAware -{ - void SetContext(IArchitectureContext context); - IArchitectureContext GetContext(); -} - -// 框架负责"提供什么" -public static class CanSendExtensions -{ - public static void SendCommand(this ICanSendCommand self, T command) - where T : ICommand - { - // 自动注入架构上下文依赖 - command.SetContext(self.GetContext()); - command.Execute(); - } -} -``` - -### 2. 接口隔离原则(ISP) - -Rule 接口遵循接口隔离原则,每个接口职责单一: - -```csharp -// ❌ 不好的设计:一个大接口包含所有能力 -public interface IBigInterface -{ - void SetContext(IArchitectureContext context); - IArchitectureContext GetContext(); - T GetModel() where T : class, IModel; - T GetSystem() where T : class, ISystem; - void SendCommand(T command) where T : ICommand; - // ... 更多方法 -} - -// ✅ 好的设计:小接口组合 -public interface IContextAware { ... } // 只负责上下文的设置与获取 -public interface ICanGetModel { ... } // 只负责获取 Model -public interface ICanSendCommand { ... } // 只负责发送 Command -``` - -### 3. 组合优于继承 - -通过接口组合实现不同能力: - -```csharp -// Controller 需要获取 Model 和发送 Command -public interface IController : ICanGetModel, ICanGetSystem, ICanSendCommand, - ICanSendQuery, ICanRegisterEvent -{ -} - -// Command 需要上下文感知和获取 Model/System -public interface ICommand : IContextAware, ICanGetModel, ICanGetSystem, - ICanSendEvent, ICanSendQuery -{ -} - -// System 只需要获取其他组件 -public interface ISystem : IContextAware, ICanGetModel, ICanGetUtility, ICanGetSystem, - ICanRegisterEvent, ICanSendEvent, ICanSendQuery -{ -} -``` - -## 扩展规则 - -### 自定义规则接口 - -```csharp -// 定义新的规则接口 -public interface ICanAccessDatabase : IBelongToArchitecture -{ -} - -// 提供扩展方法 -public static class CanAccessDatabaseExtensions -{ - public static DatabaseUtility GetDatabase(this ICanAccessDatabase self) - { - return self.GetArchitecture().GetUtility(); - } -} - -// 让特定组件实现这个接口 -public class DatabaseCommand : AbstractCommand, ICanAccessDatabase -{ - protected override void OnExecute() - { - var db = this.GetDatabase(); - // 使用数据库... - } -} -``` - -## 最佳实践 - -1. **遵循既有规则** - 优先使用框架提供的规则接口 -2. **不要绕过规则** - 不要直接存储架构引用,使用接口获取 -3. **接口组合** - 通过实现多个小接口获得所需能力 -4. **扩展规则** - 需要新能力时,定义新的规则接口 -5. **保持一致** - 自定义组件也应遵循相同的规则体系 - -## 相关包 - -- [`architecture`](../architecture/README.md) - 定义 IArchitectureContext 接口 -- [`command`](../command/README.md) - Command 继承 AbstractCommand (IContextAware) -- [`query`](../query/README.md) - Query 继承 AbstractQuery (IContextAware) -- [`controller`](../controller/README.md) - Controller 实现 ICanSendCommand 等接口 -- [`system`](../system/README.md) - System 继承 AbstractSystem (IContextAware) -- [`model`](../model/README.md) - Model 继承 AbstractModel (IContextAware) -- [`extensions`](../extensions/README.md) - 基于规则接口提供扩展方法 \ No newline at end of file diff --git a/GFramework.Core/system/README.md b/GFramework.Core/system/README.md deleted file mode 100644 index 916a1dc..0000000 --- a/GFramework.Core/system/README.md +++ /dev/null @@ -1,544 +0,0 @@ -# System 包使用说明 - -## 概述 - -System 包定义了业务逻辑层(Business Logic Layer)。System 负责处理游戏的核心业务逻辑,协调 Model 之间的交互,响应事件并执行复杂的业务流程。 - -## 核心接口 - -### [`ICanGetSystem`](ICanGetSystem.cs) - -标记接口,表示该类型可以获取其他 System。 - -**继承关系:** - -```csharp -public interface ICanGetSystem : IBelongToArchitecture -``` - -### [`ISystem`](ISystem.cs) - -System 接口,定义了系统的基本行为。 - -**核心成员:** - -```csharp -void Init(); // 系统初始化方法 -void Destroy(); // 系统销毁方法 -void OnArchitecturePhase(ArchitecturePhase phase); // 处理架构阶段事件 -``` - -**继承的能力:** - -- `ICanSetArchitecture` - 可设置架构 -- `ICanGetModel` - 可获取 Model -- `ICanGetUtility` - 可获取 Utility -- `ICanGetSystem` - 可获取其他 System -- `ICanRegisterEvent` - 可注册事件 -- `ICanSendEvent` - 可发送事件 - -## 核心类 - -### [`AbstractSystem`](AbstractSystem.cs) - -抽象 System 基类,提供了 System 的基础实现。继承自 ContextAwareBase,具有上下文感知能力。 - -**使用方式:** - -```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(); // 子类可选择重写销毁逻辑 - public virtual void OnArchitecturePhase(ArchitecturePhase phase); // 处理架构阶段事件 -} -``` - -## 基本使用 - -### 1. 定义 System - -```csharp -// 战斗系统 -public class CombatSystem : AbstractSystem -{ - protected override void OnInit() - { - // 注册事件监听 - this.RegisterEvent(OnEnemyAttack); - this.RegisterEvent(OnPlayerAttack); - } - - private void OnEnemyAttack(EnemyAttackEvent e) - { - var playerModel = this.GetModel(); - - // 计算伤害 - int damage = CalculateDamage(e.AttackPower, playerModel.Defense.Value); - - // 应用伤害 - playerModel.Health.Value -= damage; - - // 发送伤害事件 - this.SendEvent(new PlayerTookDamageEvent { Damage = damage }); - } - - private void OnPlayerAttack(PlayerAttackEvent e) - { - var playerModel = this.GetModel(); - var enemyModel = this.GetModel(); - - int damage = CalculateDamage(playerModel.AttackPower.Value, e.Enemy.Defense); - e.Enemy.Health -= damage; - - this.SendEvent(new EnemyTookDamageEvent - { - EnemyId = e.Enemy.Id, - Damage = damage - }); - } - - private int CalculateDamage(int attackPower, int defense) - { - return Math.Max(1, attackPower - defense / 2); - } - - protected override void OnDestroy() - { - // 清理资源 - base.OnDestroy(); - } -} -``` - -### 2. 注册 System - -```csharp -public class GameArchitecture : Architecture -{ - protected override void Init() - { - // 注册 Model - this.RegisterModel(new PlayerModel()); - this.RegisterModel(new EnemyModel()); - - // 注册 System(系统注册后会自动调用 Init) - this.RegisterSystem(new CombatSystem()); - this.RegisterSystem(new InventorySystem()); - this.RegisterSystem(new QuestSystem()); - } -} -``` - -### 3. 在其他组件中获取 System - -```csharp -// 在 Controller 中 -public partial class GameController : Node, IController -{ - public IArchitecture GetArchitecture() => GameArchitecture.Interface; - - public override void _Ready() - { - // 获取 System - var combatSystem = this.GetSystem(); - var questSystem = this.GetSystem(); - } -} - -// 在 Command 中 -public class StartBattleCommand : AbstractCommand -{ - protected override void OnExecute() - { - var combatSystem = this.GetSystem(); - // 使用 System... - } -} -``` - -## 常见使用模式 - -### 1. 事件驱动的 System - -```csharp -public class InventorySystem : AbstractSystem -{ - protected override void OnInit() - { - // 监听物品相关事件 - this.RegisterEvent(OnItemAdded); - this.RegisterEvent(OnItemRemoved); - this.RegisterEvent(OnItemUsed); - } - - private void OnItemAdded(ItemAddedEvent e) - { - var inventoryModel = this.GetModel(); - - // 添加物品 - inventoryModel.AddItem(e.ItemId, e.Count); - - // 检查成就 - CheckAchievements(e.ItemId); - - // 发送通知 - this.SendEvent(new ShowNotificationEvent - { - Message = $"获得物品: {e.ItemId} x{e.Count}" - }); - } - - private void OnItemUsed(ItemUsedEvent e) - { - var inventoryModel = this.GetModel(); - var playerModel = this.GetModel(); - - if (inventoryModel.HasItem(e.ItemId)) - { - // 应用物品效果 - ApplyItemEffect(e.ItemId, playerModel); - - // 移除物品 - inventoryModel.RemoveItem(e.ItemId, 1); - - this.SendEvent(new ItemEffectAppliedEvent { ItemId = e.ItemId }); - } - } - - private void ApplyItemEffect(string itemId, PlayerModel player) - { - // 物品效果逻辑... - if (itemId == "health_potion") - { - player.Health.Value = Math.Min( - player.Health.Value + 50, - player.MaxHealth.Value - ); - } - } - - private void CheckAchievements(string itemId) - { - // 成就检查逻辑... - } -} -``` - -### 2. 定时更新的 System - -```csharp -public class BuffSystem : AbstractSystem -{ - private List _activeBuffs = new(); - - protected override void OnInit() - { - this.RegisterEvent(OnBuffApplied); - this.RegisterEvent(OnUpdate); - } - - private void OnBuffApplied(BuffAppliedEvent e) - { - _activeBuffs.Add(new BuffData - { - BuffId = e.BuffId, - Duration = e.Duration, - RemainingTime = e.Duration - }); - - ApplyBuffEffect(e.BuffId, true); - } - - private void OnUpdate(GameUpdateEvent e) - { - // 更新所有 Buff - for (int i = _activeBuffs.Count - 1; i >= 0; i--) - { - var buff = _activeBuffs[i]; - buff.RemainingTime -= e.DeltaTime; - - if (buff.RemainingTime <= 0) - { - // Buff 过期 - ApplyBuffEffect(buff.BuffId, false); - _activeBuffs.RemoveAt(i); - - this.SendEvent(new BuffExpiredEvent { BuffId = buff.BuffId }); - } - } - } - - private void ApplyBuffEffect(string buffId, bool apply) - { - var playerModel = this.GetModel(); - // 应用或移除 Buff 效果... - } -} -``` - -### 3. 跨 System 协作 - -```csharp -public class QuestSystem : AbstractSystem -{ - protected override void OnInit() - { - this.RegisterEvent(OnEnemyKilled); - this.RegisterEvent(OnItemCollected); - } - - private void OnEnemyKilled(EnemyKilledEvent e) - { - var questModel = this.GetModel(); - var activeQuests = questModel.GetActiveQuests(); - - foreach (var quest in activeQuests) - { - if (quest.Type == QuestType.KillEnemy && quest.TargetId == e.EnemyType) - { - quest.Progress++; - - if (quest.Progress >= quest.RequiredAmount) - { - // 任务完成 - CompleteQuest(quest.Id); - } - } - } - } - - private void CompleteQuest(string questId) - { - var questModel = this.GetModel(); - var quest = questModel.GetQuest(questId); - - // 标记任务完成 - questModel.CompleteQuest(questId); - - // 发放奖励(通过其他 System) - this.SendEvent(new QuestCompletedEvent - { - QuestId = questId, - Rewards = quest.Rewards - }); - } -} - -public class RewardSystem : AbstractSystem -{ - protected override void OnInit() - { - this.RegisterEvent(OnQuestCompleted); - } - - private void OnQuestCompleted(QuestCompletedEvent e) - { - var playerModel = this.GetModel(); - - // 发放奖励 - foreach (var reward in e.Rewards) - { - switch (reward.Type) - { - case RewardType.Gold: - playerModel.Gold.Value += reward.Amount; - break; - case RewardType.Experience: - playerModel.Experience.Value += reward.Amount; - break; - case RewardType.Item: - this.SendEvent(new ItemAddedEvent - { - ItemId = reward.ItemId, - Count = reward.Amount - }); - break; - } - } - - this.SendEvent(new RewardsGrantedEvent { Rewards = e.Rewards }); - } -} -``` - -### 4. 管理复杂状态机 - -```csharp -public class GameStateSystem : AbstractSystem -{ - private GameState _currentState = GameState.MainMenu; - - protected override void OnInit() - { - this.RegisterEvent(OnStateChangeRequest); - } - - private void OnStateChangeRequest(GameStateChangeRequestEvent e) - { - if (CanTransition(_currentState, e.TargetState)) - { - ExitState(_currentState); - _currentState = e.TargetState; - EnterState(_currentState); - - this.SendEvent(new GameStateChangedEvent - { - PreviousState = _currentState, - NewState = e.TargetState - }); - } - } - - private bool CanTransition(GameState from, GameState to) - { - // 状态转换规则 - return (from, to) switch - { - (GameState.MainMenu, GameState.Playing) => true, - (GameState.Playing, GameState.Paused) => true, - (GameState.Paused, GameState.Playing) => true, - (GameState.Playing, GameState.GameOver) => true, - _ => false - }; - } - - private void EnterState(GameState state) - { - switch (state) - { - case GameState.Playing: - // 开始游戏 - this.SendCommand(new StartGameCommand()); - break; - case GameState.Paused: - // 暂停游戏 - this.SendEvent(new GamePausedEvent()); - break; - case GameState.GameOver: - // 游戏结束 - this.SendCommand(new GameOverCommand()); - break; - } - } - - private void ExitState(GameState state) - { - // 清理当前状态 - } -} -``` - -## System vs Model - -### Model(数据层) - -- **职责**:存储数据和状态 -- **特点**:被动,等待修改 -- **示例**:PlayerModel、InventoryModel - -### System(逻辑层) - -- **职责**:处理业务逻辑,协调 Model -- **特点**:主动,响应事件 -- **示例**:CombatSystem、QuestSystem - -```csharp -// ✅ 正确的职责划分 - -// Model: 存储数据 -public class PlayerModel : AbstractModel -{ - public BindableProperty Health { get; } = new(100); - public BindableProperty Mana { get; } = new(50); - - protected override void OnInit() { } -} - -// System: 处理逻辑 -public class CombatSystem : AbstractSystem -{ - protected override void OnInit() - { - this.RegisterEvent(OnAttack); - } - - private void OnAttack(AttackEvent e) - { - var playerModel = this.GetModel(); - - // System 负责计算和决策 - int damage = CalculateDamage(e); - playerModel.Health.Value -= damage; - - if (playerModel.Health.Value <= 0) - { - this.SendEvent(new PlayerDiedEvent()); - } - } -} -``` - -## 最佳实践 - -1. **单一职责** - 每个 System 专注于一个业务领域 -2. **事件驱动** - 通过事件与其他组件通信 -3. **无状态或少状态** - 优先将状态存储在 Model 中 -4. **可组合** - System 之间通过事件松耦合协作 -5. **初始化注册** - 在 `OnInit` 中注册所有事件监听 - -## 性能优化 - -### 1. 避免频繁的 GetModel/GetSystem - -```csharp -// ❌ 不好:每次都获取 -private void OnUpdate(GameUpdateEvent e) -{ - var model = this.GetModel(); // 频繁调用 - // ... -} - -// ✅ 好:缓存引用 -private PlayerModel _playerModel; - -protected override void OnInit() -{ - _playerModel = this.GetModel(); // 只获取一次 -} - -private void OnUpdate(GameUpdateEvent e) -{ - // 直接使用缓存的引用 - _playerModel.Health.Value += 1; -} -``` - -### 2. 批量处理 - -```csharp -public class ParticleSystem : AbstractSystem -{ - private List _particles = new(); - - private void OnUpdate(GameUpdateEvent e) - { - // 批量更新,而不是每个粒子发一个事件 - for (int i = _particles.Count - 1; i >= 0; i--) - { - UpdateParticle(_particles[i], e.DeltaTime); - } - } -} -``` - -## 相关包 - -- [`model`](../model/README.md) - System 操作 Model 的数据 -- [`events`](../events/README.md) - System 通过事件通信 -- [`command`](../command/README.md) - System 中可以发送 Command -- [`query`](../query/README.md) - System 中可以发送 Query -- [`utility`](../utility/README.md) - System 可以使用 Utility -- [`architecture`](../architecture/README.md) - 在架构中注册 System \ No newline at end of file diff --git a/GFramework.Core/utility/README.md b/GFramework.Core/utility/README.md deleted file mode 100644 index 1bc5924..0000000 --- a/GFramework.Core/utility/README.md +++ /dev/null @@ -1,613 +0,0 @@ -# Utility 包使用说明 - -## 概述 - -Utility 包定义了工具类层。Utility 提供无状态的辅助功能,如数学计算、文件操作、序列化等通用工具方法。与 System 不同,Utility -不依赖架构状态,是纯粹的工具函数集合。 - -## 核心接口 - -### IUtility - -Utility 标记接口,所有工具类都应实现此接口。 - -**接口定义:** - -```csharp -public interface IUtility -{ - // 标记接口,无方法定义 -} -``` - -### IContextUtility - -上下文工具接口,扩展了IUtility接口,为需要感知架构上下文的工具类提供基础能力。 - -**接口定义:** - -```csharp -public interface IContextUtility : IUtility -{ - void Init(); // 初始化上下文工具 -} -``` - -## 核心类 - -### [`AbstractContextUtility`](AbstractContextUtility.cs) - -抽象上下文工具类,提供上下文相关的通用功能实现。继承自 ContextAwareBase 并实现 IContextUtility 接口。 - -**使用方式:** - -```csharp -public abstract class AbstractContextUtility : ContextAwareBase, IContextUtility -{ - protected ILogger Logger = null!; - - void IContextUtility.Init() - { - var name = GetType().Name; - Logger = LoggerFactoryResolver.Provider.CreateLogger(name); - Logger.Debug($"Initializing Context Utility: {name}"); - - OnInit(); // 子类实现初始化逻辑 - - Logger.Info($"Context Utility initialized: {name}"); - } - - protected abstract void OnInit(); // 子类实现具体的初始化逻辑 -} -``` - -## 基本使用 - -### 1. 定义 Utility - -```csharp -// 存储工具类,继承自AbstractContextUtility -public class StorageUtility : AbstractContextUtility -{ - private const string SavePath = "user://save_data.json"; - - protected override void OnInit() - { - Logger.Info("StorageUtility initialized"); - } - - public void Save(T data) - { - string json = JsonSerializer.Serialize(data); - // 实际保存逻辑 - File.WriteAllText(SavePath, json); - } - - public T Load() - { - if (!File.Exists(SavePath)) - return default(T); - - string json = File.ReadAllText(SavePath); - return JsonSerializer.Deserialize(json); - } - - public void Delete() - { - if (File.Exists(SavePath)) - { - File.Delete(SavePath); - } - } -} - -// 数学工具类,作为普通Utility -public class MathUtility : IUtility -{ - public float Lerp(float a, float b, float t) - { - return a + (b - a) * Math.Clamp(t, 0f, 1f); - } - - public bool IsInRange(float value, float min, float max) - { - return value >= min && value <= max; - } -} - -// 时间工具类 -public class TimeUtility : IUtility -{ - public string FormatTime(float seconds) - { - int minutes = (int)(seconds / 60); - int secs = (int)(seconds % 60); - return $"{minutes:D2}:{secs:D2}"; - } - - public long GetCurrentTimestamp() - { - return DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - } - - public bool IsExpired(long timestamp, int durationSeconds) - { - return GetCurrentTimestamp() > timestamp + durationSeconds; - } -} -``` - -### 2. 注册 Utility - -```csharp -public class GameArchitecture : Architecture -{ - protected override void Init() - { - // 注册 Utility(不需要初始化) - this.RegisterUtility(new StorageUtility()); - this.RegisterUtility(new MathUtility()); - this.RegisterUtility(new TimeUtility()); - } -} -``` - -### 3. 使用 Utility - -```csharp -// 在 System 中使用 -public class SaveSystem : AbstractSystem -{ - protected override void OnInit() - { - this.RegisterEvent(OnSaveGame); - this.RegisterEvent(OnLoadGame); - } - - private void OnSaveGame(SaveGameEvent e) - { - var storage = this.GetUtility(); - var playerModel = this.GetModel(); - - var saveData = new SaveData - { - PlayerName = playerModel.Name.Value, - Level = playerModel.Level.Value, - Gold = playerModel.Gold.Value, - Timestamp = this.GetUtility().GetCurrentTimestamp() - }; - - storage.Save(saveData); - this.SendEvent(new GameSavedEvent()); - } - - private void OnLoadGame(LoadGameEvent e) - { - var storage = this.GetUtility(); - var saveData = storage.Load(); - - if (saveData != null) - { - var playerModel = this.GetModel(); - playerModel.Name.Value = saveData.PlayerName; - playerModel.Level.Value = saveData.Level; - playerModel.Gold.Value = saveData.Gold; - - this.SendEvent(new GameLoadedEvent()); - } - } -} - -// 在 Command 中使用 -public class MovePlayerCommand : AbstractCommand -{ - public Vector3 TargetPosition { get; set; } - public float Speed { get; set; } - - protected override void OnExecute() - { - var playerModel = this.GetModel(); - var mathUtil = this.GetUtility(); - - // 使用工具类计算 - Vector3 currentPos = playerModel.Position.Value; - Vector3 direction = (TargetPosition - currentPos).Normalized(); - Vector3 newPos = currentPos + direction * Speed; - - playerModel.Position.Value = newPos; - } -} -``` - -## 常见 Utility 类型 - -### 1. 序列化/反序列化工具 - -```csharp -public class JsonUtility : IUtility -{ - public string Serialize(T obj) - { - return Json.Stringify(obj); - } - - public T Deserialize(string json) where T : new() - { - return Json.Parse(json); - } - - public bool TryDeserialize(string json, out T result) where T : new() - { - try - { - result = Json.Parse(json); - return true; - } - catch - { - result = default; - return false; - } - } -} -``` - -### 2. 随机数工具 - -```csharp -public class RandomUtility : IUtility -{ - private Random _random = new Random(); - - public int Range(int min, int max) - { - return _random.Next(min, max + 1); - } - - public float Range(float min, float max) - { - return min + (float)_random.NextDouble() * (max - min); - } - - public T Choose(params T[] items) - { - return items[Range(0, items.Length - 1)]; - } - - public List Shuffle(List list) - { - var shuffled = new List(list); - for (int i = shuffled.Count - 1; i > 0; i--) - { - int j = Range(0, i); - (shuffled[i], shuffled[j]) = (shuffled[j], shuffled[i]); - } - return shuffled; - } - - public bool Probability(float chance) - { - return _random.NextDouble() < chance; - } -} -``` - -### 3. 字符串工具 - -```csharp -public class StringUtility : IUtility -{ - public string Truncate(string text, int maxLength, string suffix = "...") - { - if (text.Length <= maxLength) - return text; - return text.Substring(0, maxLength - suffix.Length) + suffix; - } - - public string FormatNumber(int number) - { - if (number >= 1000000) - return $"{number / 1000000.0:F1}M"; - if (number >= 1000) - return $"{number / 1000.0:F1}K"; - return number.ToString(); - } - - public string ToTitleCase(string text) - { - return System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(text.ToLower()); - } - - public bool IsValidEmail(string email) - { - return Regex.IsMatch(email, @"^[^@\s]+@[^@\s]+\.[^@\s]+$"); - } -} -``` - -### 4. 加密工具 - -```csharp -public class EncryptionUtility : IUtility -{ - private const string EncryptionKey = "YourSecretKey123"; - - public string Encrypt(string plainText) - { - byte[] data = System.Text.Encoding.UTF8.GetBytes(plainText); - byte[] encrypted = EncryptBytes(data); - return Convert.ToBase64String(encrypted); - } - - public string Decrypt(string encryptedText) - { - byte[] data = Convert.FromBase64String(encryptedText); - byte[] decrypted = DecryptBytes(data); - return System.Text.Encoding.UTF8.GetString(decrypted); - } - - private byte[] EncryptBytes(byte[] data) - { - // 简单的 XOR 加密示例(实际项目应使用更安全的算法) - byte[] key = System.Text.Encoding.UTF8.GetBytes(EncryptionKey); - byte[] result = new byte[data.Length]; - for (int i = 0; i < data.Length; i++) - { - result[i] = (byte)(data[i] ^ key[i % key.Length]); - } - return result; - } - - private byte[] DecryptBytes(byte[] data) - { - return EncryptBytes(data); // XOR 解密与加密相同 - } -} -``` - -### 5. 对象池工具 - -```csharp -public class ObjectPoolUtility : IUtility -{ - private Dictionary> _pools = new(); - - public T Get() where T : new() - { - Type type = typeof(T); - if (_pools.ContainsKey(type) && _pools[type].Count > 0) - { - return (T)_pools[type].Dequeue(); - } - return new T(); - } - - public void Return(T obj) - { - Type type = typeof(T); - if (!_pools.ContainsKey(type)) - { - _pools[type] = new Queue(); - } - _pools[type].Enqueue(obj); - } - - public void Clear() - { - Type type = typeof(T); - if (_pools.ContainsKey(type)) - { - _pools[type].Clear(); - } - } - - public void ClearAll() - { - _pools.Clear(); - } -} -``` - -### 6. 日志工具 - -```csharp -public class LogUtility : IUtility -{ - public enum LogLevel - { - Debug, - Info, - Warning, - Error - } - - public void Log(string message, LogLevel level = LogLevel.Info) - { - string prefix = level switch - { - LogLevel.Debug => "[DEBUG]", - LogLevel.Info => "[INFO]", - LogLevel.Warning => "[WARN]", - LogLevel.Error => "[ERROR]", - _ => "" - }; - - string timestamp = DateTime.Now.ToString("HH:mm:ss"); - GD.Print($"{timestamp} {prefix} {message}"); - } - - public void Debug(string message) => Log(message, LogLevel.Debug); - public void Info(string message) => Log(message, LogLevel.Info); - public void Warning(string message) => Log(message, LogLevel.Warning); - public void Error(string message) => Log(message, LogLevel.Error); -} -``` - -## Utility vs System - -### Utility(工具层) - -- **无状态** - 不存储业务数据 -- **纯函数** - 相同输入产生相同输出 -- **独立性** - 不依赖架构状态 -- **可复用** - 可在多个项目中使用 - -### System(逻辑层) - -- **有状态** - 可能存储临时状态 -- **业务逻辑** - 处理特定业务流程 -- **架构依赖** - 需要访问 Model -- **项目特定** - 针对特定项目设计 - -```csharp -// ✅ Utility: 无状态的工具方法 -public class MathUtility : IUtility -{ - public float CalculateDamage(float attackPower, float defense) - { - return Math.Max(1, attackPower - defense * 0.5f); - } -} - -// ✅ System: 有状态的业务逻辑 -public class CombatSystem : AbstractSystem -{ - private List _activeCombats = new(); - - protected override void OnInit() - { - this.RegisterEvent(OnAttack); - } - - private void OnAttack(AttackEvent e) - { - var mathUtil = this.GetUtility(); - var playerModel = this.GetModel(); - - // 使用 Utility 计算,但在 System 中处理业务逻辑 - float damage = mathUtil.CalculateDamage(e.AttackPower, playerModel.Defense.Value); - playerModel.Health.Value -= (int)damage; - - _activeCombats.Add(new CombatInstance { Damage = damage }); - } -} -``` - -## 最佳实践 - -1. **保持无状态** - Utility 不应存储业务状态 -2. **纯函数优先** - 相同输入应产生相同输出 -3. **单一职责** - 每个 Utility 专注于一类功能 -4. **避免依赖** - 不依赖 Model、System 等架构组件 -5. **可测试** - 易于单元测试的纯函数 - -## 错误示例 - -```csharp -// ❌ 错误:Utility 中存储状态 -public class BadUtility : IUtility -{ - private int _counter = 0; // 不应该有状态 - - public int GetNextId() - { - return ++_counter; // 依赖内部状态 - } -} - -// ❌ 错误:Utility 中访问 Model -public class BadUtility2 : IUtility -{ - public void DoSomething() - { - // Utility 不应该访问架构组件 - var model = this.GetModel(); // 编译错误! - } -} - -// ✅ 正确:如果需要状态,应该使用 System -public class IdGeneratorSystem : AbstractSystem -{ - private int _counter = 0; - - protected override void OnInit() { } - - public int GetNextId() - { - return ++_counter; - } -} -``` - -## 性能优化 - -### 1. 缓存计算结果 - -```csharp -public class PathfindingUtility : IUtility -{ - private Dictionary<(Vector3, Vector3), List> _pathCache = new(); - - public List FindPath(Vector3 start, Vector3 end, bool useCache = true) - { - var key = (start, end); - - if (useCache && _pathCache.ContainsKey(key)) - { - return _pathCache[key]; - } - - var path = CalculatePath(start, end); - - if (useCache) - { - _pathCache[key] = path; - } - - return path; - } - - private List CalculatePath(Vector3 start, Vector3 end) - { - // A* 算法等复杂计算... - return new List(); - } - - public void ClearCache() - { - _pathCache.Clear(); - } -} -``` - -### 2. 对象复用 - -```csharp -public class CollectionUtility : IUtility -{ - private List _tempList = new(); - - public List GetPointsInRadius(Vector3 center, float radius, List points) - { - _tempList.Clear(); - - foreach (var point in points) - { - if (point.DistanceTo(center) <= radius) - { - _tempList.Add(point); - } - } - - return new List(_tempList); // 返回副本 - } -} -``` - -## 相关包 - -- [`system`](../system/README.md) - System 中使用 Utility -- [`command`](../command/README.md) - Command 中可以使用 Utility -- [`architecture`](../architecture/README.md) - 在架构中注册 Utility -- [`ioc`](../ioc/README.md) - Utility 通过 IoC 容器管理 -- [`extensions`](../extensions/README.md) - 提供 GetUtility 扩展方法 \ No newline at end of file diff --git a/GFramework.Game.Abstractions/README.md b/GFramework.Game.Abstractions/README.md index 9ac048d..fe14fe8 100644 --- a/GFramework.Game.Abstractions/README.md +++ b/GFramework.Game.Abstractions/README.md @@ -1,14 +1,13 @@ # GFramework.Game.Abstractions -`GFramework.Game.Abstractions` 提供 `GFramework.Game` 的抽象层接口定义,用于解耦业务逻辑与具体实现。 +GFramework.Game 模块的抽象层,提供游戏业务相关的接口定义。 ## 主要内容 -- 游戏业务常用抽象(数据、场景、设置、存储、UI 等) -- 与 `GFramework.Core.Abstractions` 配合使用的接口契约 -- 供上层应用或扩展模块进行面向接口编程 +- 游戏业务常用抽象接口 +- 与 GFramework.Core.Abstractions 配合使用的契约 ## 使用建议 -- 若你需要直接使用完整游戏扩展能力,优先安装 `GeWuYou.GFramework.Game`。 -- 若你在做模块拆分、测试替身(Mock)或跨实现解耦,可单独依赖本包。 +- 若需直接使用完整游戏扩展能力,优先使用 GFramework.Game +- 若在做模块拆分或需要解耦,可单独依赖本包 diff --git a/GFramework.Game/README.md b/GFramework.Game/README.md new file mode 100644 index 0000000..e3e255e --- /dev/null +++ b/GFramework.Game/README.md @@ -0,0 +1,16 @@ +# GFramework.Game + +GFramework 框架的游戏通用模块,提供游戏开发常用的功能。 + +## 主要功能 + +- **Settings** - 游戏设置系统,支持设置分类和配置应用 + +## 依赖关系 + +- 依赖 GFramework.Core +- 依赖 GFramework.Core.Abstractions + +## 详细文档 + +参见 [docs/game/](../docs/game/) 目录下的详细文档。 diff --git a/GFramework.Game/setting/README.md b/GFramework.Game/setting/README.md deleted file mode 100644 index 12a3f1a..0000000 --- a/GFramework.Game/setting/README.md +++ /dev/null @@ -1,204 +0,0 @@ -# 设置系统 (Settings System) - -## 概述 - -设置系统是 GFramework.Game 的核心组件之一,负责管理游戏中各种设置配置。该系统采用了模型-系统分离的设计模式,支持设置部分(Section)的管理和设置应用器模式。 - -## 核心类 - -### SettingsModel - -设置模型类,继承自 `AbstractModel` 并实现 `ISettingsModel` 接口。 - -**主要功能:** - -- 管理不同类型的设置部分(Settings Section) -- 提供类型安全的设置访问 -- 支持可应用设置对象的注册 - -**关键方法:** - -- `Get()` - 获取或创建指定类型的设置部分 -- `TryGet(Type, out ISettingsSection)` - 尝试获取设置部分 -- `Register(IApplyAbleSettings)` - 注册可应用的设置对象 -- `All()` - 获取所有设置部分 - -### SettingsSystem - -设置系统类,继承自 `AbstractSystem` 并实现 `ISettingsSystem` 接口。 - -**主要功能:** - -- 应用设置配置到相应系统 -- 支持单个或批量设置应用 -- 自动识别可应用设置类型 - -**关键方法:** - -- `ApplyAll()` - 应用所有设置配置 -- `Apply()` - 应用指定类型的设置 -- `Apply(IEnumerable)` - 应用指定类型集合的设置 - -## 架构设计 - -```mermaid -graph TD - A[ISettingsModel] --> B[SettingsModel] - C[ISettingsSystem] --> D[SettingsSystem] - - B --> E[Dictionary] - D --> B - - F[ISettingsSection] --> G[IApplyAbleSettings] - H[AudioSettings] --> G - I[GraphicsSettings] --> G - - E --> H - E --> I - - J[Application] --> D - D --> G -``` - -## 使用示例 - -### 基本使用 - -```csharp -// 获取设置模型 -var settingsModel = this.GetModel(); - -// 获取或创建音频设置 -var audioSettings = settingsModel.Get(); -audioSettings.MasterVolume = 0.8f; -audioSettings.BgmVolume = 0.6f; -audioSettings.SfxVolume = 0.9f; - -// 注册设置到模型 -settingsModel.Register(audioSettings); -``` - -### 应用设置 - -```csharp -// 获取设置系统 -var settingsSystem = this.GetSystem(); - -// 应用所有设置 -await settingsSystem.ApplyAll(); - -// 应用特定类型设置 -await settingsSystem.Apply(); - -// 应用多个类型设置 -var types = new[] { typeof(GodotAudioSettings), typeof(GodotGraphicsSettings) }; -await settingsSystem.Apply(types); -``` - -### 创建自定义设置 - -```csharp -/// -/// 游戏设置类 -/// -public class GameSettings : ISettingsSection -{ - public float GameSpeed { get; set; } = 1.0f; - public int Difficulty { get; set; } = 1; - public bool AutoSave { get; set; } = true; -} - -// 使用自定义设置 -var gameSettings = settingsModel.Get(); -gameSettings.GameSpeed = 1.5f; -``` - -### 创建可应用设置 - -```csharp -/// -/// 游戏设置应用器 -/// -public class GameSettings : ISettingsSection, IApplyAbleSettings -{ - public float GameSpeed { get; set; } = 1.0f; - public int Difficulty { get; set; } = 1; - - public Task Apply() - { - // 应用游戏速度 - Time.timeScale = GameSpeed; - - // 应用难度设置 - GameDifficulty.Current = Difficulty; - - return Task.CompletedTask; - } -} -``` - -## 接口定义 - -### ISettingsSection - -```csharp -public interface ISettingsSection -{ - // 设置部分的标识接口 -} -``` - -### IApplyAbleSettings - -```csharp -public interface IApplyAbleSettings : ISettingsSection -{ - Task Apply(); -} -``` - -### ISettingsModel - -```csharp -public interface ISettingsModel -{ - T Get() where T : class, ISettingsSection, new(); - bool TryGet(Type type, out ISettingsSection section); - IEnumerable All(); - void Register(IApplyAbleSettings applyAble); -} -``` - -### ISettingsSystem - -```csharp -public interface ISettingsSystem -{ - Task ApplyAll(); - Task Apply() where T : class, ISettingsSection; - Task Apply(Type settingsType); - Task Apply(IEnumerable settingsTypes); -} -``` - -## 设计模式 - -该系统使用了以下设计模式: - -1. **Repository Pattern** - SettingsModel 作为设置数据的仓库 -2. **Command Pattern** - IApplyAbleSettings 的 Apply 方法作为命令 -3. **Factory Pattern** - Get() 方法创建设置实例 -4. **Template Method** - AbstractSystem 提供初始化模板 - -## 最佳实践 - -1. **设置分类** - 将相关设置组织到同一个设置类中 -2. **延迟应用** - 批量修改后再应用,而不是每次修改都应用 -3. **类型安全** - 使用泛型方法确保类型安全 -4. **可测试性** - 通过接口实现便于单元测试 - -## 相关链接 - -- [Godot 设置模块](../../GFramework.Godot/setting/README.md) -- [存储模块](../../GFramework.Godot/storage/README.md) -- [抽象接口定义](../../../GFramework.Core/Abstractions/) \ No newline at end of file diff --git a/GFramework.Godot.SourceGenerators/README.md b/GFramework.Godot.SourceGenerators/README.md index 4d77fc6..6da7cb3 100644 --- a/GFramework.Godot.SourceGenerators/README.md +++ b/GFramework.Godot.SourceGenerators/README.md @@ -1,14 +1,13 @@ # GFramework.Godot.SourceGenerators -`GFramework.Godot.SourceGenerators` 提供面向 Godot 场景的源码生成扩展,减少模板代码与手写样板。 +面向 Godot 场景的源码生成扩展模块,减少模板代码。 -## 主要内容 +## 主要功能 - 与 Godot 场景相关的编译期生成能力 - 基于 Roslyn 的增量生成器实现 -- 与 `GFramework.SourceGenerators` 协同工作 ## 使用建议 -- 仅在 **Godot + C#** 项目中启用。 -- 非 Godot 项目可只使用 `GeWuYou.GFramework.SourceGenerators`。 +- 仅在 Godot + C# 项目中启用 +- 非 Godot 项目可只使用 GFramework.SourceGenerators diff --git a/GFramework.Godot/README.md b/GFramework.Godot/README.md new file mode 100644 index 0000000..4f2bd47 --- /dev/null +++ b/GFramework.Godot/README.md @@ -0,0 +1,19 @@ +# GFramework.Godot + +GFramework 框架的 Godot 引擎集成模块,提供Godot特定的功能和扩展。 + +## 主要功能 + +- **Extensions** - Godot节点扩展方法,简化常见开发任务 +- **Signal** - 流畅的信号连接API,支持链式调用 +- **Storage** - Godot文件存储系统,支持虚拟路径 +- **Settings** - Godot设置系统,管理音频和图形设置 + +## 依赖关系 + +- 依赖 GFramework.Core +- 依赖 GFramework.Core.Abstractions + +## 详细文档 + +参见 [docs/godot/](../docs/godot/) 目录下的详细文档。 diff --git a/GFramework.Godot/extensions/README.md b/GFramework.Godot/extensions/README.md deleted file mode 100644 index 737c3fa..0000000 --- a/GFramework.Godot/extensions/README.md +++ /dev/null @@ -1,335 +0,0 @@ -# Godot 扩展方法 (Godot Extensions) - -## 概述 - -Godot 扩展方法模块为 Godot 引擎提供了丰富的便捷扩展方法集合。这些扩展方法简化了常见的 Godot -开发任务,提高了代码的可读性和开发效率。该模块遵循流畅接口设计原则,支持链式调用。 - -## 模块结构 - -```mermaid -graph TD - A[Extensions] --> B[GodotPathExtensions] - A --> C[NodeExtensions] - A --> D[SignalFluentExtensions] - A --> E[UnRegisterExtension] - D --> F[SignalBuilder] - - B --> G[路径判断扩展] - C --> H[节点生命周期] - C --> I[节点查询] - C --> J[场景树操作] - C --> K[输入控制] - C --> L[调试工具] - D --> M[信号连接系统] - E --> N[事件管理] -``` - -## 扩展模块详解 - -### 1. 路径扩展 (GodotPathExtensions) - -提供 Godot 虚拟路径的判断和识别功能。 - -**主要方法:** - -- `IsUserPath()` - 判断是否为 `user://` 路径 -- `IsResPath()` - 判断是否为 `res://` 路径 -- `IsGodotPath()` - 判断是否为 Godot 虚拟路径 - -**使用示例:** - -```csharp -string savePath = "user://save.dat"; -string configPath = "res://config.json"; -string logPath = "C:/logs/debug.log"; - -if (savePath.IsUserPath()) Console.WriteLine("用户数据路径"); -if (configPath.IsResPath()) Console.WriteLine("资源路径"); -if (logPath.IsGodotPath()) Console.WriteLine("Godot 虚拟路径"); -else Console.WriteLine("文件系统路径"); -``` - -### 2. 节点扩展 (NodeExtensions) - -最丰富的扩展模块,提供全面的节点操作功能。 - -#### 节点生命周期管理 - -```csharp -// 安全释放节点 -node.QueueFreeX(); // 延迟释放 -node.FreeX(); // 立即释放 - -// 等待节点就绪 -await node.WaitUntilReady(); - -// 检查节点有效性 -if (node.IsValidNode()) Console.WriteLine("节点有效"); -if (node.IsInvalidNode()) Console.WriteLine("节点无效"); -``` - -#### 节点查询操作 - -```csharp -// 查找子节点 -var sprite = node.FindChildX("Sprite"); -var parent = node.GetParentX(); - -// 获取或创建节点 -var panel = parent.GetOrCreateNode("MainPanel"); - -// 遍历子节点 -node.ForEachChild(sprite => { - sprite.Modulate = Colors.White; -}); -``` - -#### 场景树操作 - -```csharp -// 获取根节点 -var root = node.GetRootNodeX(); - -// 异步添加子节点 -await parent.AddChildX(childNode); - -// 设置场景树暂停状态 -node.Paused(true); // 暂停 -node.Paused(false); // 恢复 -``` - -#### 输入控制 - -```csharp -// 标记输入事件已处理 -node.SetInputAsHandled(); - -// 禁用/启用输入 -node.DisableInput(); -node.EnableInput(); -``` - -#### 调试工具 - -```csharp -// 打印节点路径 -node.LogNodePath(); - -// 打印节点树 -node.PrintTreeX(); - -// 安全延迟调用 -node.SafeCallDeferred("UpdateUI"); -``` - -#### 类型转换 - -```csharp -// 安全的类型转换 -var button = node.OfType