diff --git a/GFramework.Core.Abstractions/README.md b/GFramework.Core.Abstractions/README.md new file mode 100644 index 0000000..812cba2 --- /dev/null +++ b/GFramework.Core.Abstractions/README.md @@ -0,0 +1,521 @@ +# GFramework.Core.Abstractions 抽象层 + +> GFramework 框架的接口定义模块,提供所有核心组件的抽象契约 + +## 概述 + +GFramework.Core.Abstractions 是 GFramework 框架的抽象层定义模块,包含了框架中所有核心组件的接口(Interface)、枚举(Enum)和配置类(Class)。该模块采用 +`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 diff --git a/GFramework.Core.Abstractions/controller/README.md b/GFramework.Core.Abstractions/controller/README.md index 98378f5..7ab2fa9 100644 --- a/GFramework.Core.Abstractions/controller/README.md +++ b/GFramework.Core.Abstractions/controller/README.md @@ -2,8 +2,9 @@ ## 概述 -Controller 包定义了控制器(Controller)的接口规范。控制器是 MVC 架构中的 C -层,负责处理用户交互、协调视图和模型,是连接表现层和业务层的桥梁。在本框架中,Controller 通常对应 Godot 的节点脚本。 +Controller 包定义了控制器(Controller)的接口规范。控制器是 MVC 架构中的 C 层,负责处理用户交互、协调视图和模型,是连接表现层和业务层的桥梁。 + +**注意**:本框架使用依赖注入模式,Controller 通过构造函数或属性注入获取架构实例,而非使用全局单例。 ## 核心接口 @@ -33,51 +34,53 @@ Controller 包定义了控制器(Controller)的接口规范。控制器是 M ## 使用示例 -### 基础控制器实现 +### 基础控制器实现(依赖注入模式) ```csharp -using Godot; -using GFramework.framework.controller; -using GFramework.framework.architecture; +using GFramework.Core.architecture; -// Godot 节点控制器 -public partial class PlayerController : Node, IController +// 通过依赖注入获取架构 +public class PlayerController : IController { - private IUnRegisterList _unregisterList = new UnRegisterList(); + private readonly IArchitecture _architecture; + private readonly IUnRegisterList _unregisterList = new UnRegisterList(); - // 实现架构获取 - public IArchitecture GetArchitecture() => GameArchitecture.Interface; + // 通过构造函数注入架构 + public PlayerController(IArchitecture architecture) + { + _architecture = architecture; + } - public override void _Ready() + public void Initialize() { // 获取模型 - var playerModel = this.GetModel(); + var playerModel = _architecture.GetModel(); // 监听模型变化 playerModel.Health.RegisterWithInitValue(OnHealthChanged) .AddToUnregisterList(_unregisterList); // 注册事件 - this.RegisterEvent(OnPlayerLevelUp) + _architecture.RegisterEvent(OnPlayerLevelUp) .AddToUnregisterList(_unregisterList); } // 处理用户输入 - public override void _Process(double delta) + public void ProcessInput(double delta) { if (Input.IsActionJustPressed("attack")) { // 发送命令 - this.SendCommand(new AttackCommand()); + _architecture.SendCommand(new AttackCommand()); } if (Input.IsActionJustPressed("use_item")) { // 发送查询 - var inventory = this.SendQuery(new GetInventoryQuery()); + var inventory = _architecture.SendQuery(new GetInventoryQuery()); if (inventory.HasItem("potion")) { - this.SendCommand(new UseItemCommand("potion")); + _architecture.SendCommand(new UseItemCommand("potion")); } } } @@ -94,7 +97,7 @@ public partial class PlayerController : Node, IController ShowLevelUpEffect(); } - public override void _ExitTree() + public void Cleanup() { // 清理事件注册 _unregisterList.UnRegisterAll(); @@ -109,15 +112,16 @@ public partial class PlayerController : Node, IController ```csharp // UI 面板控制器 -public partial class MainMenuController : Control, IController +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 IArchitecture GetArchitecture() => GameArchitecture.Interface; - - public override void _Ready() + public void Initialize() { // 绑定按钮事件 _startButton.Pressed += OnStartButtonPressed; @@ -125,30 +129,29 @@ public partial class MainMenuController : Control, IController _quitButton.Pressed += OnQuitButtonPressed; // 获取模型更新 UI - var gameModel = this.GetModel(); + var gameModel = _architecture.GetModel(); UpdateUI(gameModel); } private void OnStartButtonPressed() { // 通过命令启动游戏 - this.SendCommand(); + _architecture.SendCommand(); } private void OnSettingsButtonPressed() { // 查询当前设置 - var settings = this.SendQuery(new GetSettingsQuery()); + var settings = _architecture.SendQuery(new GetSettingsQuery()); // 打开设置面板 - var uiSystem = this.GetSystem(); - uiSystem.OpenSettingsPanel(settings); + _uiSystem.OpenSettingsPanel(settings); } private void OnQuitButtonPressed() { // 发送退出命令 - this.SendCommand(); + _architecture.SendCommand(); } private void UpdateUI(GameModel model) { /* UI 更新逻辑 */ } @@ -159,25 +162,26 @@ public partial class MainMenuController : Control, IController ```csharp // 战斗控制器 -public partial class CombatController : Node, IController +public class CombatController : IController { + [Inject] protected IArchitecture _architecture; + private IUnRegisterList _unregisterList = new UnRegisterList(); private PlayerModel _playerModel; private CombatSystem _combatSystem; - public IArchitecture GetArchitecture() => GameArchitecture.Interface; - - public override void _Ready() + [PostConstruct] + public void Init() { // 缓存常用引用 - _playerModel = this.GetModel(); - _combatSystem = this.GetSystem(); + _playerModel = _architecture.GetModel(); + _combatSystem = _architecture.GetSystem(); // 注册多个事件 - this.RegisterEvent(OnEnemySpawned) + _architecture.RegisterEvent(OnEnemySpawned) .AddToUnregisterList(_unregisterList); - this.RegisterEvent(OnCombatEnded) + _architecture.RegisterEvent(OnCombatEnded) .AddToUnregisterList(_unregisterList); // 监听模型状态 @@ -188,7 +192,7 @@ public partial class CombatController : Node, IController private void OnEnemySpawned(EnemySpawnedEvent e) { // 进入战斗状态 - this.SendCommand(new EnterCombatCommand(e.Enemy)); + _architecture.SendCommand(new EnterCombatCommand(e.Enemy)); } private void OnCombatEnded(CombatEndedEvent e) @@ -196,26 +200,25 @@ public partial class CombatController : Node, IController if (e.Victory) { // 查询奖励 - var rewards = this.SendQuery(new CalculateRewardsQuery(e.Enemy)); + var rewards = _architecture.SendQuery(new CalculateRewardsQuery(e.Enemy)); // 发放奖励 - this.SendCommand(new GiveRewardsCommand(rewards)); + _architecture.SendCommand(new GiveRewardsCommand(rewards)); } else { // 处理失败 - this.SendCommand(); + _architecture.SendCommand(); } } private void OnCombatStateChanged(CombatState state) { // 根据战斗状态更新 UI - var uiSystem = this.GetSystem(); - uiSystem.UpdateCombatUI(state); + _architecture.GetSystem().UpdateCombatUI(state); } - public override void _ExitTree() + public void Cleanup() { _unregisterList.UnRegisterAll(); } @@ -267,107 +270,74 @@ public partial class CombatController : Node, IController ### 事件注销 ```csharp -public partial class MyController : Node, IController +public class MyController : IController { + [Inject] private IArchitecture _architecture; + // 使用 UnRegisterList 统一管理 private IUnRegisterList _unregisterList = new UnRegisterList(); - public override void _Ready() + public void Initialize() { // 所有事件注册都添加到列表 - this.RegisterEvent(OnGameEvent) + _architecture.RegisterEvent(OnGameEvent) .AddToUnregisterList(_unregisterList); - this.GetModel().Health.Register(OnHealthChanged) + _architecture.GetModel().Health.Register(OnHealthChanged) .AddToUnregisterList(_unregisterList); } - public override void _ExitTree() + public void Cleanup() { - // 节点销毁时统一注销所有事件 + // 统一注销所有事件 _unregisterList.UnRegisterAll(); } } ``` -### Godot 特定的生命周期 - -```csharp -public partial class GameController : Node, IController -{ - public IArchitecture GetArchitecture() => GameArchitecture.Interface; - - // 节点进入场景树 - public override void _Ready() - { - // 初始化控制器 - InitializeController(); - } - - // 每帧更新 - public override void _Process(double delta) - { - // 处理实时输入 - HandleInput(); - } - - // 物理帧更新 - public override void _PhysicsProcess(double delta) - { - // 处理物理相关输入 - } - - // 节点即将退出场景树 - public override void _ExitTree() - { - // 清理资源 - CleanupController(); - } -} -``` - ## 最佳实践 -1. **一个控制器对应一个视图** - - 每个 Godot 场景/节点有对应的控制器 - - 避免一个控制器管理多个不相关的视图 +1. **使用依赖注入获取依赖** + - 通过构造函数注入 `IArchitecture` + - 使用 `[Inject]` 属性标记注入字段 -2. **使用依赖注入获取依赖** - - 通过 `GetModel()`、`GetSystem()` 获取依赖 - - 不要在构造函数中获取,应在 `_Ready()` 中 - -3. **保持控制器轻量** +2. **保持控制器轻量** - 复杂逻辑放在 Command、Query、System 中 - 控制器只做协调和转发 -4. **合理使用缓存** +3. **合理使用缓存** - 频繁使用的 Model、System 可以缓存引用 - 平衡性能和内存占用 -5. **统一管理事件注销** +4. **统一管理事件注销** - 使用 `IUnRegisterList` 统一管理 - - 在 `_ExitTree()` 中统一注销 + - 在 `Cleanup()` 中统一注销 -6. **命名规范** +5. **命名规范** - 控制器类名:`XxxController` - - 继承 Godot 节点:`Node`、`Control`、`Node2D` 等 + - 使用 `[Inject]` 或构造函数注入获取架构 ## 常见模式 ### 数据绑定模式 ```csharp -public partial class ScoreController : Label, IController +public class ScoreController : IController { - public IArchitecture GetArchitecture() => GameArchitecture.Interface; + [Inject] private IArchitecture _architecture; - public override void _Ready() + public void Initialize() { // 绑定模型数据到 UI - this.GetModel() + _architecture.GetModel() .Score - .RegisterWithInitValue(score => Text = $"Score: {score}") - .UnRegisterWhenNodeExitTree(this); + .RegisterWithInitValue(score => UpdateDisplay(score)) + .AddToUnregisterList(_unregisterList); + } + + private void UpdateDisplay(int score) + { + // 更新分数显示 } } ``` @@ -375,11 +345,12 @@ public partial class ScoreController : Label, IController ### 状态机模式 ```csharp -public partial class PlayerStateController : Node, IController +public class PlayerStateController : IController { + [Inject] private IArchitecture _architecture; private Dictionary _stateHandlers; - public override void _Ready() + public void Initialize() { _stateHandlers = new Dictionary { @@ -388,10 +359,10 @@ public partial class PlayerStateController : Node, IController { PlayerState.Attacking, HandleAttackingState } }; - this.GetModel() + _architecture.GetModel() .State .Register(OnStateChanged) - .UnRegisterWhenNodeExitTree(this); + .AddToUnregisterList(_unregisterList); } private void OnStateChanged(PlayerState state) @@ -401,6 +372,31 @@ public partial class PlayerStateController : Node, IController } ``` +## 与 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) - 提供架构访问能力 @@ -409,4 +405,9 @@ public partial class PlayerStateController : Node, IController - [`events`](../events/README.md) - 控制器注册事件监听变化 - [`model`](../model/README.md) - 控制器读取模型数据 - [`system`](../system/README.md) - 控制器调用系统服务 -- [`extensions`](../extensions/README.md) - 提供便捷的扩展方法 \ No newline at end of file +- [`extensions`](../extensions/README.md) - 提供便捷的扩展方法 +- **GFramework.Godot** - Godot 特定的控制器扩展 + +--- + +**许可证**: Apache 2.0 diff --git a/GFramework.Core/README.md b/GFramework.Core/README.md index 126c0c6..cb63464 100644 --- a/GFramework.Core/README.md +++ b/GFramework.Core/README.md @@ -1,8 +1,8 @@ -# Framework 架构框架 +# GFramework.Core 核心框架 > 一个基于 CQRS、MVC 和事件驱动的轻量级游戏开发架构框架 -## 📖 目录 +## 目录 - [框架概述](#框架概述) - [核心概念](#核心概念) @@ -11,26 +11,31 @@ - [包说明](#包说明) - [组件联动](#组件联动) - [最佳实践](#最佳实践) -- [示例项目](#示例项目) +- [设计理念](#设计理念) ## 框架概述 -本框架是一个专为 Godot C# 游戏开发设计的轻量级架构,它结合了多种经典设计模式: +本框架是一个与平台无关的轻量级架构,它结合了多种经典设计模式: - **MVC 架构模式** - 清晰的层次划分 - **CQRS 模式** - 命令查询职责分离 - **IoC/DI** - 依赖注入和控制反转 - **事件驱动** - 松耦合的组件通信 - **响应式编程** - 可绑定属性和数据流 +- **阶段式生命周期管理** - 精细化的架构状态控制 + +**重要说明**:GFramework.Core 是与平台无关的核心模块,不包含任何 Godot 特定代码。Godot 集成功能在 GFramework.Godot 包中实现。 ### 核心特性 -✅ **清晰的分层架构** - Model、View、Controller、System、Utility 各司其职 -✅ **类型安全** - 基于泛型的组件获取和事件系统 -✅ **松耦合** - 通过事件和接口实现组件解耦 -✅ **易于测试** - 依赖注入和纯函数设计 -✅ **可扩展** - 基于接口的规则体系 -✅ **生命周期管理** - 自动的注册和注销机制 +- **清晰的分层架构** - Model、View、Controller、System、Utility 各司其职 +- **类型安全** - 基于泛型的组件获取和事件系统 +- **松耦合** - 通过事件和接口实现组件解耦 +- **易于测试** - 依赖注入和纯函数设计 +- **可扩展** - 基于接口的规则体系 +- **生命周期管理** - 自动的注册和注销机制 +- **模块化** - 支持架构模块安装 +- **平台无关** - Core 模块可以在任何 .NET 环境中使用 ## 核心概念 @@ -38,7 +43,7 @@ ``` ┌─────────────────────────────────────────┐ -│ View (Godot Nodes) │ UI 层:Godot 节点 +│ View / UI │ UI 层:用户界面 ├─────────────────────────────────────────┤ │ Controller │ 控制层:处理用户输入 ├─────────────────────────────────────────┤ @@ -58,33 +63,40 @@ Query ──┼──→ 跨层操作(修改/查询数据) Event ──┘ ``` +### 架构阶段 + +``` +初始化:Init → BeforeUtilityInit → AfterUtilityInit → BeforeModelInit → AfterModelInit → BeforeSystemInit → AfterSystemInit → Ready +销毁:Destroy → Destroying → Destroyed +``` + ## 架构图 ### 整体架构 ``` - ┌──────────────────┐ - │ Architecture │ ← 单例,管理所有组件 - └────────┬─────────┘ - │ - ┌────────────────────┼────────────────────┐ - │ │ │ - ┌───▼────┐ ┌───▼────┐ ┌───▼─────┐ - │ Model │ │ System │ │ Utility │ - │ 层 │ │ 层 │ │ 层 │ - └───┬────┘ └───┬────┘ └────────┘ - │ │ - │ ┌─────────────┤ - │ │ │ - ┌───▼────▼───┐ ┌───▼──────┐ - │ Controller │ │ Command/ │ - │ 层 │ │ Query │ - └─────┬──────┘ └──────────┘ - │ - ┌─────▼─────┐ - │ View │ - │ (Godot节点)│ - └───────────┘ + ┌──────────────────┐ + │ Architecture │ ← 管理所有组件 + └────────┬─────────┘ + │ + ┌────────────────────┼────────────────────┐ + │ │ │ + ┌───▼────┐ ┌───▼────┐ ┌───▼─────┐ + │ Model │ │ System │ │ Utility │ + │ 层 │ │ 层 │ │ 层 │ + └───┬────┘ └───┬────┘ └────────┘ + │ │ + │ ┌─────────────┤ + │ │ │ + ┌───▼────▼───┐ ┌───▼──────┐ + │ Controller │ │ Command/ │ + │ 层 │ │ Query │ + └─────┬──────┘ └──────────┘ + │ + ┌─────▼─────┐ + │ View │ + │ UI │ + └───────────┘ ``` ### 数据流向 @@ -97,52 +109,52 @@ Event ──┘ ## 快速开始 -本框架采用"约定优于配置"的设计理念,只需 4 步即可搭建完整的游戏架构。 +本框架采用"约定优于配置"的设计理念,只需 4 步即可搭建完整的架构。 ### 为什么需要这个框架? -在传统的 Godot 开发中,我们经常遇到这些问题: +在传统开发中,我们经常遇到这些问题: -- 💔 **代码耦合严重**:UI 直接访问游戏逻辑,逻辑直接操作 UI -- 🔄 **难以维护**:修改一个功能需要改动多个文件 -- 🐛 **难以测试**:业务逻辑和 UI 混在一起无法独立测试 -- 📦 **难以复用**:代码紧密耦合,无法在其他项目中复用 +- 代码耦合严重:UI 直接访问游戏逻辑,逻辑直接操作 UI +- 难以维护:修改一个功能需要改动多个文件 +- 难以测试:业务逻辑和 UI 混在一起无法独立测试 +- 难以复用:代码紧密耦合,无法在其他项目中复用 本框架通过清晰的分层解决这些问题。 ### 1. 定义架构(Architecture) -**作用**:Architecture 是整个游戏的"中央调度器",负责管理所有组件的生命周期。 +**作用**:Architecture 是整个应用的"中央调度器",负责管理所有组件的生命周期。 ```csharp -using GFramework.framework.architecture; +using GFramework.Core.architecture; -public class GameArchitecture : Architecture +public class GameArchitecture : Architecture { protected override void Init() { // 注册 Model - 游戏数据 - this.RegisterModel(new PlayerModel()); + RegisterModel(new PlayerModel()); // 注册 System - 业务逻辑 - this.RegisterSystem(new CombatSystem()); + RegisterSystem(new CombatSystem()); // 注册 Utility - 工具类 - this.RegisterUtility(new StorageUtility()); + RegisterUtility(new StorageUtility()); } } ``` **优势**: -- ✅ **单例模式**:通过 `GameArchitecture.Interface` 全局访问 -- ✅ **自动初始化**:注册时自动调用组件的 Init 方法 -- ✅ **依赖注入**:组件自动获得架构引用,无需手动传递 -- ✅ **集中管理**:所有组件注册在一处,一目了然 +- **依赖注入**:组件通过上下文获取架构引用 +- **集中管理**:所有组件注册在一处,一目了然 +- **生命周期管理**:自动初始化和销毁 +- **平台无关**:可以在任何 .NET 环境中使用 ### 2. 定义 Model(数据层) -**作用**:Model 是游戏的"数据库",只负责存储和管理游戏状态。 +**作用**:Model 是应用的"数据库",只负责存储和管理状态。 ```csharp public class PlayerModel : AbstractModel @@ -160,11 +172,12 @@ public class PlayerModel : AbstractModel }); } } -//当然也可以不这样 + +// 也可以不使用 BindableProperty public class PlayerModel : AbstractModel { - public int Health { get;private set; } - public int Gold { get;private set; } + public int Health { get; private set; } + public int Gold { get; private set; } protected override void OnInit() { @@ -176,19 +189,13 @@ public class PlayerModel : AbstractModel **优势**: -- ✅ **数据响应式**:BindableProperty 让数据变化自动通知 UI -- ✅ **职责单一**:只存储数据,不包含复杂业务逻辑 -- ✅ **易于测试**:可以独立测试数据逻辑 -- ✅ **数据持久化**:可以轻松序列化整个 Model 进行存档 - -**为什么不在 Model 中写业务逻辑?** - -- 保持 Model 简单纯粹,业务逻辑应该在 System 中处理 -- Model 应该是"被动"的,等待其他组件修改它 +- **数据响应式**:BindableProperty 让数据变化自动通知监听者 +- **职责单一**:只存储数据,不包含复杂业务逻辑 +- **易于测试**:可以独立测试数据逻辑 ### 3. 定义 System(业务逻辑层) -**作用**:System 是游戏的"大脑",处理所有业务逻辑。 +**作用**:System 是应用的"大脑",处理所有业务逻辑。 ```csharp public class CombatSystem : AbstractSystem @@ -214,68 +221,58 @@ public class CombatSystem : AbstractSystem **优势**: -- ✅ **事件驱动**:通过事件解耦,不同 System 之间松耦合 -- ✅ **可组合**:多个 System 协同工作,每个专注自己的领域 -- ✅ **易于扩展**:新增功能只需添加新的 System 和事件监听 -- ✅ **独立测试**:可以模拟事件来测试 System 的逻辑 - -**System 与 Model 的关系**: - -- System 读取和修改 Model 的数据 -- System 不应该存储重要的游戏状态(状态应在 Model 中) -- System 可以存储临时的计算结果或缓存 +- **事件驱动**:通过事件解耦,不同 System 之间松耦合 +- **可组合**:多个 System 协同工作,每个专注自己的领域 +- **易于扩展**:新增功能只需添加新的 System 和事件监听 ### 4. 定义 Controller(控制层) -**作用**:Controller 是"桥梁",连接 UI(View)和业务逻辑。 +**作用**:Controller 是"桥梁",连接 UI 和业务逻辑。 ```csharp -public partial class PlayerController : Node, IController +public class PlayerController : IController { - [Export] private Label _healthLabel; - private IUnRegisterList _unregisterList = new UnRegisterList(); + // 通过依赖注入获取架构 + private readonly IArchitecture _architecture; - // 实现接口,连接到架构 - public IArchitecture GetArchitecture() => GameArchitecture.Interface; - - public override void _Ready() + public PlayerController(IArchitecture architecture) { - var playerModel = this.GetModel(); + _architecture = architecture; + } + + // 监听模型变化 + public void Initialize() + { + var playerModel = _architecture.GetModel(); // 数据绑定:Model 数据变化自动更新 UI - playerModel.Health - .RegisterWithInitValue(hp => _healthLabel.Text = $"HP: {hp}") - .AddToUnregisterList(_unregisterList); + playerModel.Health.RegisterWithInitValue(OnHealthChanged); } - public override void _ExitTree() + private void OnHealthChanged(int hp) { - // 重要:节点销毁时注销所有监听,避免内存泄漏 - _unregisterList.UnRegisterAll(); + // 更新 UI 显示 + UpdateHealthDisplay(hp); } + + private void UpdateHealthDisplay(int hp) { /* UI 更新逻辑 */ } } ``` **优势**: -- ✅ **自动更新 UI**:通过 BindableProperty,数据变化自动反映到界面 -- ✅ **生命周期管理**:自动注销监听,避免内存泄漏 -- ✅ **分离关注点**:UI 逻辑和业务逻辑完全分离 -- ✅ **易于修改 UI**:改变 UI 不影响业务逻辑 - -**为什么使用 RegisterWithInitValue?** - -- 注册监听时立即获得当前值,避免 UI 显示空白 -- 后续数据变化会自动触发更新 +- **自动更新 UI**:通过 BindableProperty,数据变化自动反映到界面 +- **分离关注点**:UI 逻辑和业务逻辑完全分离 +- **易于测试**:可以通过依赖注入模拟架构进行测试 ### 完成!现在你有了一个完整的架构 这 4 步完成后,你就拥有了: -- 📦 **清晰的数据层**(Model) -- 🧠 **独立的业务逻辑**(System) -- 🎮 **灵活的控制层**(Controller) -- 🔧 **统一的生命周期管理**(Architecture) +- **清晰的数据层**(Model) +- **独立的业务逻辑**(System) +- **灵活的控制层**(Controller) +- **统一的生命周期管理**(Architecture) ### 下一步该做什么? @@ -283,46 +280,49 @@ public partial class PlayerController : Node, IController 2. **添加 Query**:封装数据查询(如查询背包物品数量) 3. **添加更多 System**:如任务系统、背包系统、商店系统 4. **使用 Utility**:添加工具类(如存档工具、数学工具) +5. **使用模块**:通过 IArchitectureModule 扩展架构功能 ## 包说明 -| 包名 | 职责 | 文档 | -|------------------|-----------------|---------------------------------| -| **architecture** | 架构核心,管理所有组件生命周期 | [📖 查看](architecture/README.md) | -| **model** | 数据模型层,存储游戏状态 | [📖 查看](model/README.md) | -| **system** | 业务逻辑层,处理游戏系统 | [📖 查看](system/README.md) | -| **controller** | 控制器层,连接视图和逻辑 | [📖 查看](controller/README.md) | -| **utility** | 工具类层,提供无状态工具 | [📖 查看](utility/README.md) | -| **command** | 命令模式,封装写操作 | [📖 查看](command/README.md) | -| **query** | 查询模式,封装读操作 | [📖 查看](query/README.md) | -| **events** | 事件系统,组件间通信 | [📖 查看](events/README.md) | -| **property** | 可绑定属性,响应式编程 | [📖 查看](property/README.md) | -| **ioc** | IoC 容器,依赖注入 | [📖 查看](ioc/README.md) | -| **rule** | 规则接口,定义组件约束 | [📖 查看](rule/README.md) | -| **extensions** | 扩展方法,简化 API 调用 | [📖 查看](extensions/README.md) | +| 包名 | 职责 | 文档 | +|------------------|-----------------|------------------------------| +| **architecture** | 架构核心,管理所有组件生命周期 | [查看](architecture/README.md) | +| **constants** | 框架常量定义 | 本文档 | +| **model** | 数据模型层,存储状态 | [查看](model/README.md) | +| **system** | 业务逻辑层,处理业务规则 | [查看](system/README.md) | +| **controller** | 控制器层,连接视图和逻辑 | (在 Abstractions 中) | +| **utility** | 工具类层,提供无状态工具 | [查看](utility/README.md) | +| **command** | 命令模式,封装写操作 | [查看](command/README.md) | +| **query** | 查询模式,封装读操作 | [查看](query/README.md) | +| **events** | 事件系统,组件间通信 | [查看](events/README.md) | +| **property** | 可绑定属性,响应式编程 | [查看](property/README.md) | +| **ioc** | IoC 容器,依赖注入 | [查看](ioc/README.md) | +| **rule** | 规则接口,定义组件约束 | [查看](rule/README.md) | +| **extensions** | 扩展方法,简化 API 调用 | [查看](extensions/README.md) | +| **logging** | 日志系统,记录运行日志 | [查看](logging/README.md) | +| **environment** | 环境接口,提供运行环境信息 | [查看](environment/README.md) | ## 组件联动 ### 1. 初始化流程 ``` -Architecture.Interface +创建 Architecture 实例 └─> Init() - ├─> RegisterModel → Model.SetArchitecture() → Model.Init() - ├─> RegisterSystem → System.SetArchitecture() → System.Init() - └─> RegisterUtility (无需初始化) + ├─> RegisterModel → Model.SetContext() → Model.Init() + ├─> RegisterSystem → System.SetContext() → System.Init() + └─> RegisterUtility → Utility 注册到容器 ``` ### 2. Command 执行流程 ``` Controller.SendCommand(command) - └─> command.SetArchitecture(architecture) // 自动注入 - └─> command.Execute() - └─> command.OnExecute() // 子类实现 - ├─> GetModel() // 获取数据 - ├─> 修改 Model 数据 - └─> SendEvent() // 发送事件 + └─> command.Execute() + └─> command.OnDo() // 子类实现 + ├─> GetModel() // 获取数据 + ├─> 修改 Model 数据 + └─> SendEvent() // 发送事件 ``` ### 3. Event 传播流程 @@ -341,34 +341,29 @@ Controller.SendCommand(command) ``` Model: BindableProperty Health = new(100); Controller: Health.RegisterWithInitValue(hp => UpdateUI(hp)) -修改值: Health.Value = 50 → 触发所有回调 → UI 自动更新 +修改值: Health.Value = 50 → 触发所有回调 → 更新 UI ``` ## 最佳实践 -掌握这些最佳实践,能让你充分发挥框架的优势,避免常见陷阱。 - -### 1. 分层职责原则 📋 +### 1. 分层职责原则 每一层都有明确的职责边界,遵循这些原则能让代码更清晰、更易维护。 -#### ✅ 好的实践 vs ❌ 坏的实践 - **Model 层**: ```csharp -// ✅ 好:只存储数据 +// 好:只存储数据 public class PlayerModel : AbstractModel { public BindableProperty Health { get; } = new(100); - public BindableProperty MaxHealth { get; } = new(100); protected override void OnInit() { } } -// ❌ 坏:包含业务逻辑 +// 坏:包含业务逻辑 public class PlayerModel : AbstractModel { - public void TakeDamage(int damage) // ❌ 业务逻辑应在 System + public void TakeDamage(int damage) // 业务逻辑应在 System { Health.Value -= damage; if (Health.Value <= 0) Die(); @@ -379,7 +374,7 @@ public class PlayerModel : AbstractModel **System 层**: ```csharp -// ✅ 好:处理业务逻辑 +// 好:处理业务逻辑 public class CombatSystem : AbstractSystem { protected override void OnInit() @@ -389,560 +384,88 @@ public class CombatSystem : AbstractSystem private void OnAttack(AttackEvent e) { - // 业务逻辑在这里 var target = this.GetModel(); int finalDamage = CalculateDamage(e.BaseDamage, target); target.Health.Value -= finalDamage; } } - -// ❌ 坏:直接操作 UI -public class CombatSystem : AbstractSystem -{ - private Label _damageLabel; // ❌ 不应持有 UI 引用 - - private void OnAttack(AttackEvent e) - { - _damageLabel.Text = $"-{e.Damage}"; // ❌ 应通过事件通知 - } -} ``` -**Controller 层**: +### 2. 通信方式选择指南 -```csharp -// ✅ 好:只处理 UI 和用户输入 -public partial class AttackButton : Button, IController -{ - public override void _Ready() - { - Pressed += () => this.SendCommand(new AttackCommand()); - } -} +| 通信方式 | 使用场景 | 优势 | +|----------------------|-----------|----------| +| **Command** | 用户操作、修改状态 | 可撤销、可记录 | +| **Query** | 查询数据、检查条件 | 明确只读意图 | +| **Event** | 通知其他组件 | 松耦合、可扩展 | +| **BindableProperty** | 数据变化通知 | 自动化、不会遗漏 | -// ❌ 坏:包含业务逻辑 -public partial class AttackButton : Button, IController -{ - public override void _Ready() - { - Pressed += () => - { - var player = this.GetModel(); - var enemy = this.GetModel(); - - // ❌ 这些业务逻辑应该在 System/Command 中 - int damage = player.AttackPower.Value - enemy.Defense.Value; - enemy.Health.Value -= damage; - }; - } -} -``` - -### 2. 通信方式选择指南 💬 - -不同的通信方式适用于不同场景,选对方式能让代码更优雅。 - -| 通信方式 | 使用场景 | 示例 | 优势 | -|----------------------|------------|----------------|----------| -| **Command** | 用户操作、修改状态 | 购买物品、攻击敌人 | 可撤销、可记录 | -| **Query** | 查询数据、检查条件 | 查询金币数量、检查是否可购买 | 明确只读意图 | -| **Event** | 通知其他组件 | 玩家死亡、物品拾取 | 松耦合、可扩展 | -| **BindableProperty** | 数据→UI 自动同步 | 生命值变化更新血条 | 自动化、不会遗漏 | - -**实战示例:购物系统** - -```csharp -// 1. Controller:用户点击购买按钮 -public void OnBuyButtonPressed() -{ - // 先用 Query 检查条件 - bool canBuy = this.SendQuery(new CanBuyItemQuery - { - ItemId = "sword", - Price = 100 - }); - - if (canBuy) - { - // 使用 Command 执行操作 - this.SendCommand(new BuyItemCommand { ItemId = "sword" }); - } - else - { - ShowMessage("金币不足!"); - } -} - -// 2. Query:检查是否可以购买 -public class CanBuyItemQuery : AbstractQuery -{ - public string ItemId { get; set; } - public int Price { get; set; } - - protected override bool OnDo() - { - var player = this.GetModel(); - return player.Gold.Value >= Price; - } -} - -// 3. Command:执行购买 -public class BuyItemCommand : AbstractCommand -{ - public string ItemId { get; set; } - - protected override void OnExecute() - { - var player = this.GetModel(); - var shop = this.GetModel(); - - int price = shop.GetPrice(ItemId); - player.Gold.Value -= price; - - // 发送事件通知 - this.SendEvent(new ItemPurchasedEvent { ItemId = ItemId }); - } -} - -// 4. System:响应购买事件 -public class InventorySystem : AbstractSystem -{ - protected override void OnInit() - { - this.RegisterEvent(OnItemPurchased); - } - - private void OnItemPurchased(ItemPurchasedEvent e) - { - var inventory = this.GetModel(); - inventory.AddItem(e.ItemId); - } -} - -// 5. Controller:通过 BindableProperty 自动更新 UI -public partial class GoldDisplay : Label, IController -{ - public override void _Ready() - { - var player = this.GetModel(); - - // 金币变化自动更新 UI - player.Gold - .RegisterWithInitValue(gold => Text = $"金币: {gold}") - .UnRegisterWhenNodeExitTree(this); - } -} -``` - -### 3. 生命周期管理 ♻️ +### 3. 生命周期管理 **为什么需要注销?** 忘记注销监听器会导致: -- 💥 **内存泄漏**:对象无法被 GC 回收 -- 🐛 **逻辑错误**:已销毁的对象仍在响应事件 -- 📉 **性能下降**:无用的监听器消耗资源 - -#### 方式一:自动注销(推荐用于 Godot 节点) - -```csharp -public override void _Ready() -{ - // 节点退出场景树时自动注销 - this.RegisterEvent(OnEvent) - .UnRegisterWhenNodeExitTree(this); - - playerModel.Health - .RegisterWithInitValue(UpdateHealthBar) - .UnRegisterWhenNodeExitTree(this); -} -``` - -**优势**:一行代码搞定,不会忘记 - -#### 方式二:统一管理(推荐用于多个监听器) +- **内存泄漏**:对象无法被 GC 回收 +- **逻辑错误**:已销毁的对象仍在响应事件 ```csharp +// 使用 UnRegisterList 统一管理 private IUnRegisterList _unregisterList = new UnRegisterList(); -public override void _Ready() +public void Initialize() { - // 所有监听器统一管理 this.RegisterEvent(OnEvent1) .AddToUnregisterList(_unregisterList); - this.RegisterEvent(OnEvent2) - .AddToUnregisterList(_unregisterList); - - playerModel.Health - .RegisterWithInitValue(UpdateUI) + model.Property.Register(OnPropertyChanged) .AddToUnregisterList(_unregisterList); } -public override void _ExitTree() +public void Cleanup() { - // 一次性注销所有 _unregisterList.UnRegisterAll(); } ``` -**优势**:集中管理,清晰明了 - -#### 方式三:手动注销(需要精确控制时机) +### 4. 性能优化技巧 ```csharp -private IUnRegister _healthUnregister; +// 低效:每帧都查询 +var model = _architecture.GetModel(); // 频繁调用 -public override void _Ready() -{ - _healthUnregister = playerModel.Health.Register(UpdateUI); -} - -public void StopListening() -{ - // 在特定时机手动注销 - _healthUnregister?.UnRegister(); - _healthUnregister = null; -} -``` - -**优势**:可以在任何时候注销 - -### 4. 性能优化技巧 ⚡ - -#### 技巧 1:缓存组件引用 - -```csharp -// ❌ 低效:每帧都查询 -public override void _Process(double delta) -{ - var model = this.GetModel(); // 每帧查询 IoC 容器 - UpdateUI(model.Health.Value); -} - -// ✅ 高效:只查询一次 +// 高效:缓存引用 private PlayerModel _playerModel; -public override void _Ready() +public void Initialize() { - _playerModel = this.GetModel(); // 只查询一次 -} - -public override void _Process(double delta) -{ - UpdateUI(_playerModel.Health.Value); + _playerModel = _architecture.GetModel(); // 只查询一次 } ``` -**原因**:GetModel 需要查询 IoC 容器,虽然很快但不必要重复查询 - -#### 技巧 2:批量操作避免频繁触发 - -```csharp -// ❌ 低效:每次修改都触发事件 -foreach (var item in 100items) -{ - inventory.AddItem(item); // 触发100次 UI 更新! -} - -// ✅ 高效:批量操作后统一通知 -foreach (var item in items) -{ - inventory.Items.SetValueWithoutEvent( - inventory.Items.Value + item - ); -} -// 最后统一触发一次 -this.SendEvent(new InventoryChangedEvent()); -``` - -**原因**:每次数据变化都会触发所有监听器,批量操作会导致性能问题 - -#### 技巧 3:使用对象池 - -```csharp -// 在 Utility 中实现对象池 -public class PoolUtility : IUtility -{ - private Dictionary> _pools = new(); - - public T Get() where T : new() - { - var type = typeof(T); - if (_pools.ContainsKey(type) && _pools[type].Count > 0) - return (T)_pools[type].Dequeue(); - return new T(); - } - - public void Return(T obj) - { - var type = typeof(T); - if (!_pools.ContainsKey(type)) - _pools[type] = new Queue(); - _pools[type].Enqueue(obj); - } -} - -// 使用对象池 -var pool = this.GetUtility(); -var bullet = pool.Get(); -// 使用完毕后归还 -pool.Return(bullet); -``` - -### 5. 可测试性设计 🧪 - -框架天然支持单元测试,因为所有组件都是通过接口交互的。 - -```csharp -[TestFixture] -public class CombatSystemTests -{ - private TestArchitecture _architecture; - private PlayerModel _player; - private CombatSystem _combat; - - [SetUp] - public void Setup() - { - // 1. 创建测试架构 - _architecture = new TestArchitecture(); - - // 2. 注册需要的组件 - _player = new PlayerModel(); - _architecture.RegisterModel(_player); - - _combat = new CombatSystem(); - _architecture.RegisterSystem(_combat); - } - - [Test] - public void TestPlayerTakesDamage() - { - // 3. 设置初始状态 - _player.Health.Value = 100; - - // 4. 触发事件 - _architecture.SendEvent(new EnemyAttackEvent { Damage = 30 }); - - // 5. 验证结果 - Assert.AreEqual(70, _player.Health.Value); - } - - [TearDown] - public void TearDown() - { - _architecture = null; - } -} -``` - -**优势**: - -- 不需要启动游戏就能测试逻辑 -- 可以快速验证各种边界情况 -- 易于进行回归测试 - -## 示例项目 - -通过一个完整的 RPG 战斗系统示例,展示框架各组件如何协同工作。 - -### 完整示例:RPG 战斗系统 ⚔️ - -实现功能:回合制战斗、伤害计算、战斗日志、胜负判定、UI 实时更新。 - -```csharp -// 架构定义 -public class RPGArchitecture : Architecture -{ - protected override void Init() - { - this.RegisterModel(new PlayerModel()); - this.RegisterModel(new EnemyModel()); - this.RegisterSystem(new CombatSystem()); - this.RegisterUtility(new MathUtility()); - } -} - -// 数据层 -public class PlayerModel : AbstractModel -{ - public BindableProperty Health { get; } = new(100); - public BindableProperty AttackPower { get; } = new(20); - public BindableProperty IsAlive { get; } = new(true); - - protected override void OnInit() - { - Health.Register(hp => - { - IsAlive.Value = hp > 0; - if (hp <= 0) this.SendEvent(new PlayerDiedEvent()); - }); - } -} - -// 业务逻辑层 -public class CombatSystem : AbstractSystem -{ - protected override void OnInit() - { - this.RegisterEvent(OnPlayerAttack); - } - - private void OnPlayerAttack(PlayerAttackEvent e) - { - var player = this.GetModel(); - var enemy = this.GetModel(); - var mathUtil = this.GetUtility(); - - int damage = mathUtil.CalculateDamage(player.AttackPower.Value, enemy.Defense.Value); - enemy.Health.Value -= damage; - - this.SendEvent(new DamageDealtEvent { Damage = damage }); - } -} - -// 控制层 -public partial class BattleUI : Control, IController -{ - [Export] private Label _healthLabel; - [Export] private Button _attackButton; - private IUnRegisterList _unregisterList = new UnRegisterList(); - - public IArchitecture GetArchitecture() => RPGArchitecture.Interface; - - public override void _Ready() - { - var player = this.GetModel(); - - // 数据绑定:自动更新 UI - player.Health - .RegisterWithInitValue(hp => _healthLabel.Text = $"HP: {hp}") - .AddToUnregisterList(_unregisterList); - - _attackButton.Pressed += () => this.SendCommand(new AttackCommand()); - } - - public override void _ExitTree() => _unregisterList.UnRegisterAll(); -} -``` - -**扩展示例**:添加技能系统只需新增 Model 和 System,无需修改现有代码。 - -```csharp -// 新增技能系统 -public class SkillSystem : AbstractSystem -{ - protected override void OnInit() - { - this.RegisterEvent(OnUseSkill); - } - - private void OnUseSkill(UseSkillEvent e) - { - // 技能逻辑 - } -} - -// 在架构中注册 -protected override void Init() -{ - this.RegisterSystem(new SkillSystem()); - // 现有代码无需修改 -} -``` - -**优势总结**: - -- 数据驱动,易于存档 -- 事件解耦,易于扩展 -- UI 自动化,不会遗漏更新 -- 可独立测试业务逻辑 - ## 设计理念 -框架的设计遵循 SOLID 原则和经典设计模式,让代码更易维护和扩展。 +框架的设计遵循 SOLID 原则和经典设计模式。 -### 1. 单一职责原则(SRP)💼 - -**理念**:每个类只负责一件事,只有一个改变的理由。 - -**在框架中的体现**: +### 1. 单一职责原则(SRP) - **Model**:只负责存储数据 - **System**:只负责处理业务逻辑 -- **Controller**:只负责 UI 交互 +- **Controller**:只负责协调和输入处理 - **Utility**:只负责提供工具方法 -**好处**: - -- 代码更容易理解和维护 -- 修改一个功能不会影响其他功能 -- 单元测试更简单 - -### 2. 开闭原则(OCP)🔓 - -**理念**:对扩展开放,对修改封闭。 - -**在框架中的实现**: +### 2. 开闭原则(OCP) - 通过**事件系统**添加新功能,无需修改现有代码 - 新的 System 可以监听现有事件,插入自己的逻辑 -- 符合"插件式"的架构设计 -**示例**: - -```csharp -// 现有:战斗系统 -public class CombatSystem : AbstractSystem -{ - private void OnAttack(AttackEvent e) - { - // 计算伤害 - this.SendEvent(new DamageDealtEvent { Damage = damage }); - } -} - -// 扩展:添加暴击系统,不修改 CombatSystem -public class CriticalSystem : AbstractSystem -{ - protected override void OnInit() - { - this.RegisterEvent(OnDamage); - } - - private void OnDamage(DamageDealtEvent e) - { - if (RollCritical()) - { - this.SendEvent(new CriticalHitEvent { Damage = e.Damage * 2 }); - } - } -} -``` - -### 3. 依赖倒置原则(DIP)🔄 - -**理念**:依赖抽象(接口)而非具体实现。 - -**在框架中的应用**: +### 3. 依赖倒置原则(DIP) - 所有组件通过接口交互 - 通过 IoC 容器注入依赖 - 易于替换实现和编写测试 -**好处**: - -- 降低耦合度 -- 易于进行单元测试(可以 mock) -- 可以灵活替换实现 - -### 4. 接口隔离原则(ISP)✂️ - -**理念**:使用多个专门的接口,而不是一个庞大的接口。 - -**在框架中的体现**: +### 4. 接口隔离原则(ISP) ```csharp // 小而专注的接口 @@ -950,195 +473,35 @@ public interface ICanGetModel : IBelongToArchitecture { } public interface ICanSendCommand : IBelongToArchitecture { } public interface ICanRegisterEvent : IBelongToArchitecture { } -// Controller 组合需要的能力 +// 组合需要的能力 public interface IController : ICanGetModel, ICanSendCommand, ICanRegisterEvent { } ``` -**优势**: +### 5. 组合优于继承 -- 类只需要实现它真正需要的方法 -- 接口更容易理解和使用 -- 减少不必要的依赖 +通过接口组合获得能力,而不是通过继承。 -### 5. 组合优于继承 🧩 +### 框架核心设计模式 -**理念**:通过接口组合获得能力,而不是通过继承。 +| 设计模式 | 应用位置 | 解决的问题 | 带来的好处 | +|-----------|------------|----------|--------| +| **工厂模式** | IoC 容器 | 组件的创建和管理 | 解耦创建逻辑 | +| **观察者模式** | Event 系统 | 组件间的通信 | 松耦合通信 | +| **命令模式** | Command | 封装操作请求 | 支持撤销重做 | +| **策略模式** | System | 不同的业务逻辑 | 易于切换策略 | +| **依赖注入** | 整体架构 | 组件间的依赖 | 自动管理依赖 | +| **模板方法** | Abstract 类 | 定义算法骨架 | 统一流程规范 | -**传统继承的问题**: +### 平台无关性 -- 继承层次深,难以理解 -- 子类与父类紧密耦合 -- 难以灵活组合能力 - -**框架的解决方案**: - -```csharp -// ✅ 通过接口组合能力 -public interface IController : - ICanGetModel, // 组合:获取 Model 的能力 - ICanSendCommand, // 组合:发送 Command 的能力 - ICanRegisterEvent // 组合:注册事件的能力 -{ } - -// ❌ 避免深层继承 -public class BaseController { } -public class GameController : BaseController { } -public class BattleController : GameController { } -``` - -### 框架核心设计模式 🎨 - -| 设计模式 | 应用位置 | 解决的问题 | 带来的好处 | -|-----------|--------------|-----------|---------| -| **单例模式** | Architecture | 全局唯一的架构实例 | 统一的组件管理 | -| **工厂模式** | IoC 容器 | 组件的创建和管理 | 解耦创建逻辑 | -| **观察者模式** | Event 系统 | 组件间的通信 | 松耦合通信 | -| **命令模式** | Command | 封装操作请求 | 支持撤销重做 | -| **策略模式** | System | 不同的业务逻辑 | 易于切换策略 | -| **依赖注入** | 整体架构 | 组件间的依赖 | 自动管理依赖 | -| **模板方法** | Abstract 类 | 定义算法骨架 | 统一流程规范 | - -### 为什么这样设计?🤔 - -#### 1. 降低学习成本 - -- 遵循业界标准模式和原则 -- 有经验的开发者能快速上手 -- 清晰的分层易于理解 - -#### 2. 提高代码质量 - -- 强制分层,避免意大利面代码 -- 职责明确,减少 bug -- 易于 Code Review - -#### 3. 便于团队协作 - -- 清晰的职责划分,减少冲突 -- 统一的代码风格 -- 新人容易融入项目 - -#### 4. 易于维护扩展 - -- 符合 SOLID 原则 -- 通过事件添加功能无需修改现有代码 -- 模块化设计,易于替换 - -#### 5. 支持单元测试 - -- 依赖注入让 mock 变得简单 -- 接口设计便于测试 -- 业务逻辑与 UI 分离,可独立测试 - -### 架构演进建议 🚀 - -#### 小型项目(< 5000 行代码) - -- 使用基础的 MVC 分层 -- 适度使用 Command 和 Query -- 事件系统用于关键通知 - -#### 中型项目(5000-20000 行) - -- 完整使用框架所有特性 -- 细分 System 的职责 -- 引入更多 Utility 复用代码 - -#### 大型项目(> 20000 行) - -- 考虑按功能模块拆分多个 Architecture -- 使用事件总线连接不同模块 -- 引入领域驱动设计(DDD)概念 - -### 常见反模式 ⚠️ - -#### 反模式 1:上帝类(God Class) - -```csharp -// ❌ 一个类做所有事情 -public class GameManager -{ - public void Attack() { } - public void Move() { } - public void SaveGame() { } - public void LoadGame() { } - public void UpdateUI() { } - // ... 几千行代码 -} - -// ✅ 正确:分层设计 -public class CombatSystem { /* 只负责战斗 */ } -public class MovementSystem { /* 只负责移动 */ } -public class SaveSystem { /* 只负责存档 */ } -``` - -#### 反模式 2:循环依赖 - -```csharp -// ❌ A 依赖 B,B 又依赖 A -public class SystemA -{ - private SystemB _systemB; -} -public class SystemB -{ - private SystemA _systemA; -} - -// ✅ 正确:通过事件解耦 -public class SystemA -{ - protected override void OnInit() - { - this.SendEvent(new EventA()); - } -} -public class SystemB -{ - protected override void OnInit() - { - this.RegisterEvent(OnEventA); - } -} -``` - -#### 反模式 3:过度设计 - -```csharp -// ❌ 简单功能过度抽象 -public interface IClickable { } -public interface IHoverable { } -public interface IFocusable { } -public class Button : IClickable, IHoverable, IFocusable { } - -// ✅ 正确:根据实际需求设计 -public class Button : Control, IController -{ - // 简单直接 -} -``` - -### 设计哲学总结 📝 - -1. **简单优于复杂**:能用简单方案就不用复杂方案 -2. **显式优于隐式**:让代码意图明确 -3. **解耦优于耦合**:通过接口和事件降低耦合 -4. **组合优于继承**:灵活组合能力而非深层继承 -5. **约定优于配置**:遵循框架约定,减少配置 - -**记住**:好的架构不是一开始就完美的,而是在迭代中不断演进的。从简单开始,根据项目需求逐步采用框架特性。 - -## 相关资源 - -- Godot 官方文档: https://docs.godotengine.org/ -- CQRS 模式介绍: https://martinfowler.com/bliki/CQRS.html -- 事件驱动架构: https://martinfowler.com/articles/201701-event-driven.html +- **GFramework.Core**:纯 .NET 库,无任何平台特定代码 +- **GFramework.Godot**:Godot 特定实现,包含 Node 扩展、GodotLogger 等 +- 可以轻松将 Core 框架移植到其他平台(Unity、.NET MAUI 等) --- **版本**: 1.0.0 -**适用引擎**: Godot 4.x (C#) -**许可证**: Apache 2.0 \ No newline at end of file +**许可证**: Apache 2.0 diff --git a/GFramework.Core/architecture/README.md b/GFramework.Core/architecture/README.md index c093cea..0e157cb 100644 --- a/GFramework.Core/architecture/README.md +++ b/GFramework.Core/architecture/README.md @@ -4,9 +4,11 @@ Architecture 包是整个框架的核心,提供了基于 MVC 架构模式的应用程序架构基础。它实现了依赖注入(IoC)容器、组件生命周期管理,以及命令、查询、事件的统一调度机制。 -## 核心类 +**注意**:本框架的 Core 模块与 Godot 解耦,Godot 相关集成在 GFramework.Godot 包中实现。 -### 1. [`IArchitecture`](IArchitecture.cs) +## 核心接口 + +### [`IArchitecture`](IArchitecture.cs) 架构接口,定义了框架的核心功能契约。 @@ -21,18 +23,18 @@ Architecture 包是整个框架的核心,提供了基于 MVC 架构模式的 **核心方法:** ```csharp -// 注册组件 -void RegisterSystem(T system) where T : ISystem; -void RegisterModel(T model) where T : IModel; -void RegisterUtility(T utility) where T : IUtility; +// 组件注册 +void RegisterSystem(TSystem system) where TSystem : ISystem; +void RegisterModel(TModel model) where TModel : IModel; +void RegisterUtility(TUtility utility) where TUtility : IUtility; -// 获取组件 +// 组件获取 T GetSystem() where T : class, ISystem; T GetModel() where T : class, IModel; T GetUtility() where T : class, IUtility; // 命令处理 -void SendCommand(T command) where T : ICommand; +void SendCommand(ICommand command); TResult SendCommand(ICommand command); // 查询处理 @@ -45,32 +47,94 @@ IUnRegister RegisterEvent(Action onEvent); void UnRegisterEvent(Action onEvent); ``` -### 2. [`Architecture`](Architecture.cs) +### [`IArchitecturePhaseAware`](IArchitecturePhaseAware.cs) -架构基类,实现了 [`IArchitecture`](IArchitecture.cs) 接口,提供完整的架构功能实现。 +架构阶段感知接口,允许组件监听架构阶段变化。 + +**核心方法:** + +```csharp +void OnArchitecturePhase(ArchitecturePhase phase); +``` + +### [`IArchitectureModule`](IArchitectureModule.cs) + +架构模块接口,支持模块化架构扩展。 + +**核心方法:** + +```csharp +void Install(IArchitecture architecture); +``` + +### [`IAsyncInitializable`](IAsyncInitializable.cs) + +异步初始化接口,支持组件异步初始化。 + +**核心方法:** + +```csharp +Task InitializeAsync(); +``` + +## 核心类 + +### [`Architecture`](Architecture.cs) + +架构基类,实现了 `IArchitecture` 接口,提供完整的架构功能实现。 **特性:** -- **单例模式**:使用泛型和 `Lazy` 确保全局唯一实例 -- **线程安全**:采用 `LazyThreadSafetyMode.ExecutionAndPublication` 保证多线程安全 -- **生命周期管理**:自动管理 System 和 Model 的初始化顺序 -- **IoC 容器**:内置依赖注入容器,管理所有组件实例 -- **事件系统**:集成类型化事件系统,支持类型安全的事件通信 +- **阶段式生命周期管理** + :支持多个架构阶段(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. 创建架构实例 +1. 创建架构实例(传入配置或使用默认配置) 2. 调用用户自定义的 `Init()` 方法 -3. 执行注册的补丁逻辑(`OnRegisterPatch`) -4. 初始化所有已注册的 Model -5. 初始化所有已注册的 System -6. 标记初始化完成 +3. 初始化上下文工具(Context Utility) +4. 初始化所有注册的 Model +5. 初始化所有注册的 System +6. 冻结 IOC 容器 +7. 进入 Ready 阶段 + +**销毁流程:** + +1. 进入 Destroying 阶段 +2. 发送 `ArchitectureDestroyingEvent` 事件 +3. 销毁所有 System +4. 进入 Destroyed 阶段 +5. 发送 `ArchitectureDestroyedEvent` 事件 **使用示例:** ```csharp -// 1. 定义你的架构 -public class GameArchitecture : Architecture +// 1. 定义你的架构(继承 Architecture 基类) +public class GameArchitecture : Architecture { protected override void Init() { @@ -88,26 +152,39 @@ public class GameArchitecture : Architecture } } -// 2. 在其他地方使用架构 +// 2. 创建并初始化架构 +var architecture = new GameArchitecture(); +architecture.Initialize(); + +// 或者异步初始化 +// var architecture = new GameArchitecture(); +// await architecture.InitializeAsync(); + +// 3. 通过依赖注入使用架构 +// 在 Controller 或其他组件中注入架构实例 public class GameController : IController { - private IArchitecture _architecture; + private readonly IArchitecture _architecture; - public IArchitecture GetArchitecture() => GameArchitecture.Interface; + // 通过构造函数注入架构 + public GameController(IArchitecture architecture) + { + _architecture = architecture; + } public void Start() { // 获取 Model - var playerModel = this.GetModel(); + var playerModel = _architecture.GetModel(); // 发送命令 - this.SendCommand(); + _architecture.SendCommand(new StartGameCommand()); // 发送查询 - var score = this.SendQuery(new GetScoreQuery()); + var score = _architecture.SendQuery(new GetScoreQuery()); // 注册事件 - this.RegisterEvent(OnPlayerDied); + _architecture.RegisterEvent(OnPlayerDied); } private void OnPlayerDied(PlayerDiedEvent e) @@ -120,51 +197,113 @@ public class GameController : IController **高级特性:** ```csharp -// 动态扩展架构(补丁系统) -Architecture.OnRegisterPatch += arch => +// 1. 使用自定义配置 +var config = new ArchitectureConfiguration(); +var architecture = new GameArchitecture(configuration: config); + +// 2. 模块安装 +var module = new GameModule(); +architecture.InstallModule(module); + +// 3. 监听架构阶段变化 +public class GamePhaseListener : IArchitecturePhaseAware { - // 在架构初始化完成前注入额外逻辑 - arch.RegisterSystem(new DebugSystem()); + 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 newSystem = new DynamicSystem(); -GameArchitecture.Interface.RegisterSystem(newSystem); -// newSystem.Init() 会被立即调用 +var architecture = new GameArchitecture(configuration: config); ``` +### [`ArchitectureServices`](ArchitectureServices.cs) + +架构服务类,管理命令总线、查询总线、IOC容器和类型事件系统。 + +### [`ArchitectureContext`](ArchitectureContext.cs) + +架构上下文类,提供对架构服务的访问。 + +### [`GameContext`](GameContext.cs) + +游戏上下文类,管理架构上下文与类型的绑定关系。 + ## 设计模式 -### 单例模式 +### 1. 依赖注入 -通过泛型约束和 `Lazy` 实现类型安全的单例。 +通过构造函数注入或容器解析获取架构实例。 -### 依赖注入(IoC) +### 2. 依赖注入(IoC) 使用内置 IoC 容器管理组件生命周期和依赖关系。 -### 命令模式 +### 3. 命令模式 -通过 [`ICommand`](../command/ICommand.cs) 封装所有用户操作。 +通过 `ICommand` 封装所有用户操作。 -### 查询模式(CQRS) +### 4. 查询模式(CQRS) -通过 [`IQuery`](../query/IQuery.cs) 分离查询和命令操作。 +通过 `IQuery` 分离查询和命令操作。 -### 观察者模式 +### 5. 观察者模式 通过事件系统实现组件间的松耦合通信。 +### 6. 阶段式生命周期管理 + +通过 `ArchitecturePhase` 枚举和生命周期钩子管理架构状态。 + +### 7. 组合优于继承 + +通过接口组合获得不同能力,而不是深层继承链。 + ## 最佳实践 1. **保持架构类简洁**:只在 `Init()` 中注册组件,不要包含业务逻辑 2. **合理划分职责**: - - Model:数据和状态 - - System:业务逻辑和规则 - - Utility:无状态的工具方法 -3. **使用接口访问**:通过 `Interface` 属性访问架构,便于测试 + - Model:数据和状态 + - System:业务逻辑和规则 + - Utility:无状态的工具方法 +3. **使用依赖注入**:通过构造函数注入架构实例,便于测试 4. **事件命名规范**:使用过去式命名事件类,如 `PlayerDiedEvent` 5. **避免循环依赖**:System 不应直接引用 System,应通过事件通信 +6. **使用模块扩展**:通过 `IArchitectureModule` 实现架构的可扩展性 +7. **Core 模块与平台解耦**:GFramework.Core 不包含 Godot 相关代码,Godot 集成在单独模块中 ## 相关包 @@ -175,7 +314,8 @@ GameArchitecture.Interface.RegisterSystem(newSystem); - [`model`](../model/README.md) - 数据模型 - [`system`](../system/README.md) - 业务系统 - [`utility`](../utility/README.md) - 工具类 +- **GFramework.Godot** - Godot 特定集成(GodotNode 扩展、GodotLogger 等) --- -**许可证**: Apache 2.0 \ No newline at end of file +**许可证**: Apache 2.0 diff --git a/GFramework.Core/logging/README.md b/GFramework.Core/logging/README.md index 4cd1fac..f78446c 100644 --- a/GFramework.Core/logging/README.md +++ b/GFramework.Core/logging/README.md @@ -1,305 +1,309 @@ -# GFramework.Core 日志系统 +# Logging 包使用说明 ## 概述 -GFramework.Core 提供了一个灵活、可配置的日志系统,支持多级别、多类别和多种输出方式的日志记录。默认日志级别为 `Info` -,确保框架的关键操作都能被记录下来。 +Logging 包提供了灵活的日志系统,支持多级别日志记录。默认日志级别为 `Info`,确保框架的关键操作都能被记录下来。 -## 主要特性 +## 核心接口 -- **多级别日志支持**: Trace、Debug、Info、Warning、Error、Fatal -- **类别化日志**: 支持按模块分类记录日志 -- **可配置输出**: 支持控制台输出和文件输出 -- **彩色控制台输出**: 提供不同级别的颜色区分 -- **灵活的级别控制**: 可全局设置或按类别设置不同的日志级别 +### [`ILogger`](ILogger.cs) -## 快速开始 +日志记录器接口,定义了日志记录的基本功能。 -### 1. 基本配置 +**核心方法:** ```csharp -using GFramework.Core.logging; +// 日志级别检查 +bool IsTraceEnabled(); +bool IsDebugEnabled(); +bool IsInfoEnabled(); +bool IsWarnEnabled(); +bool IsErrorEnabled(); +bool IsFatalEnabled(); -// 快速配置(推荐) -Log.Configure( - minLevel: LogLevel.Info, // 默认级别为Info - enableConsole: true, // 启用控制台输出 - useColors: true, // 使用彩色输出 - enableFile: false, // 不启用文件输出 - logFilePath: null // 无文件输出 -); +// 记录日志 +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); -// 或者使用详细的配置 -var config = new LogConfig +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`](ILoggerFactory.cs) + +日志工厂提供程序接口,用于获取日志工厂。 + +**核心方法:** + +```csharp +ILoggerFactory GetLoggerFactory(); +ILogger CreateLogger(string name); +``` + +### [`LogLevel`](LogLevel.cs) + +日志级别枚举。 + +```csharp +public enum LogLevel { - DefaultMinLevel = LogLevel.Info, - EnableConsole = true, - UseColors = true, - EnableFile = true, - LogFilePath = "logs/gframework.log" -}; - -// 设置特定模块的日志级别 -config.SetCategoryLevel("Architecture", LogLevel.Debug); -config.SetCategoryLevel("IOC", LogLevel.Debug); -config.SetCategoryLevel("Event", LogLevel.Info); - -Log.Initialize(config); + Trace = 0, // 最详细的跟踪信息 + Debug = 1, // 调试信息 + Info = 2, // 一般信息(默认级别) + Warning = 3, // 警告信息 + Error = 4, // 错误信息 + Fatal = 5 // 致命错误 +} ``` -### 2. 使用日志记录 +## 核心类 -#### 基本使用示例 +### [`AbstractLogger`](AbstractLogger.cs) + +抽象日志基类,封装了日志级别判断、格式化与异常处理逻辑。平台日志器只需实现 `Write` 方法即可。 + +**使用示例:** ```csharp -// 使用全局日志实例 -Log.Info("应用程序启动"); -Log.Warn("这是一个警告"); -Log.Error("这是一个错误信息"); - -// 创建特定类别的日志记录器 -var userLogger = Log.CreateLogger("UserService"); -userLogger.Info("用户服务初始化完成", new { ServiceVersion = "1.0" }); - -var dbLogger = Log.CreateLogger("Database"); -dbLogger.Debug("连接数据库", new { Server = "localhost", Database = "MyApp" }); -dbLogger.Info("数据库连接成功"); -``` - -#### 详细使用示例 - -```csharp -// 创建特定类别的日志记录器 -var logger = Log.CreateLogger("MyModule"); - -logger.Debug("调试信息:连接数据库"); -logger.Info("用户登录成功", new { UserId = 123, UserName = "张三" }); -logger.Warn("连接超时,正在重试", new { RetryCount = 2 }); -logger.Error("数据库连接失败", ex, new { DatabaseUrl = "localhost:1433" }); -logger.Fatal("系统发生严重错误", new { SystemState = "Critical" }); -``` - -#### 框架组件日志示例 - -```csharp -// 在架构中使用 -var architecture = ExampleArchitecture.Instance; -architecture.RegisterSystem(new ExampleSystem()); -architecture.RegisterModel(new ExampleModel()); -architecture.RegisterUtility(new ExampleUtility()); - -// 在系统中使用 -public class ExampleSystem : AbstractSystem +public class CustomLogger : AbstractLogger { - protected override void OnInit() + public CustomLogger(string? name = null, LogLevel minLevel = LogLevel.Info) + : base(name, minLevel) { - Log.CreateLogger("System").Info("ExampleSystem 初始化完成"); } - - protected override void OnDestroy() + + protected override void Write(LogLevel level, string message, Exception? exception) { - Log.CreateLogger("System").Info("ExampleSystem 销毁"); + // 自定义日志输出逻辑 + var logMessage = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [{level}] {message}"; + if (exception != null) + logMessage += $"\n{exception}"; + + Console.WriteLine(logMessage); } } - -// 在模型中使用 -public class ExampleModel : AbstractModel -{ - protected override void OnInit() - { - Log.CreateLogger("Model").Info("ExampleModel 初始化完成"); - } -} - -// 在工具中使用 -public class ExampleUtility : IUtility -{ - public void DoSomething() - { - Log.CreateLogger("Utility").Debug("ExampleUtility 执行操作"); - } -} - -// 在事件中使用 -architecture.RegisterEvent(evt => -{ - Log.CreateLogger("EventListener").Info($"收到事件: {evt.Message}"); -}); ``` -### 3. 高级配置 +### [`ConsoleLogger`](ConsoleLogger.cs) + +控制台日志记录器实现,支持彩色输出。 + +**使用示例:** ```csharp -// 创建自定义配置的日志记录器 -var config = new LogConfig -{ - DefaultMinLevel = LogLevel.Warning, // 默认只显示Warning及以上 - EnableConsole = true, - UseColors = true, - EnableFile = true, - LogFilePath = "logs/app-{yyyy-MM-dd}.log" -}; +// 创建控制台日志记录器 +var logger = new ConsoleLogger("MyLogger", LogLevel.Debug); -// 为不同模块设置不同的日志级别 -config.SetCategoryLevel("Architecture", LogLevel.Info); // 架构信息 -config.SetCategoryLevel("IOC", LogLevel.Debug); // IOC详细日志 -config.SetCategoryLevel("Event", LogLevel.Info); // 事件日志 -config.SetCategoryLevel("System", LogLevel.Info); // 系统日志 -config.SetCategoryLevel("Database", LogLevel.Debug); // 数据库日志 -config.SetCategoryLevel("Network", LogLevel.Trace); // 网络日志(最详细) - -Log.Initialize(config); - -// 演示不同级别的日志记录 -var networkLogger = Log.CreateLogger("Network"); -networkLogger.Trace("网络请求开始", new { Url = "https://api.example.com/users", Method = "GET" }); -networkLogger.Debug("添加请求头", new { Headers = new[] { "Authorization: Bearer xxx", "Content-Type: application/json" } }); -networkLogger.Info("网络请求完成", new { StatusCode = 200, ResponseTime = "120ms" }); - -var userServiceLogger = Log.CreateLogger("UserService"); -userServiceLogger.Debug("查询用户信息", new { UserId = 123 }); -userServiceLogger.Info("用户登录成功", new { UserId = 123, UserName = "张三", LoginTime = DateTime.Now }); +// 记录不同级别的日志 +logger.Info("应用程序启动"); +logger.Debug("调试信息"); +logger.Warn("警告信息"); +logger.Error("错误信息"); +logger.Fatal("致命错误"); ``` -### 4. 异常日志记录 - -```csharp -var serviceLogger = Log.CreateLogger("UserService"); - -try -{ - // 模拟业务逻辑中的异常 - throw new InvalidOperationException("用户数据验证失败"); -} -catch (Exception ex) -{ - serviceLogger.Error("用户注册失败", ex, new - { - Operation = "UserRegistration", - UserEmail = "user@example.com", - ValidationErrors = new[] { "邮箱格式无效", "密码强度不足" } - }); -} - -// 演示Fatal级别的使用 -try -{ - throw new SystemException("数据库连接完全中断"); -} -catch (Exception ex) -{ - serviceLogger.Fatal("系统发生致命错误", ex, new - { - ErrorCode = "DB_CONNECTION_FAILED", - RetryAttempts = 3, - LastRetryTime = DateTime.Now.AddMinutes(-5) - }); -} -``` - -### 5. 生产环境配置 - -```csharp -// 生产环境推荐配置 -var productionConfig = new LogConfig -{ - DefaultMinLevel = LogLevel.Info, // 只记录Info及以上级别 - EnableConsole = false, // 生产环境通常不输出到控制台 - UseColors = false, - EnableFile = true, // 启用文件日志 - LogFilePath = "logs/production-{yyyy-MM-dd}.log" -}; - -// 为关键模块设置更详细的日志级别 -productionConfig.SetCategoryLevel("Architecture", LogLevel.Info); -productionConfig.SetCategoryLevel("Security", LogLevel.Debug); // 安全相关日志更详细 -productionConfig.SetCategoryLevel("Payment", LogLevel.Debug); // 支付相关日志更详细 -productionConfig.SetCategoryLevel("IOC", LogLevel.Warning); // 减少IOC调试日志 - -Log.Initialize(productionConfig); - -var securityLogger = Log.CreateLogger("Security"); -securityLogger.Info("用户登录尝试", new { UserId = 456, IpAddress = "192.168.1.100" }); -securityLogger.Warn("密码错误", new { UserId = 456, FailedAttempts = 2 }); -securityLogger.Info("登录成功", new { UserId = 456, SessionId = "sess_abc123" }); - -var paymentLogger = Log.CreateLogger("Payment"); -paymentLogger.Debug("开始处理支付", new { OrderId = "ORD_789", Amount = 99.99m, Currency = "CNY" }); -paymentLogger.Info("支付成功", new { OrderId = "ORD_789", TransactionId = "txn_456" }); -``` - -## 日志级别说明 - -- **Trace**: 最详细的跟踪信息,用于调试复杂的执行流程 -- **Debug**: 调试信息,用于开发和测试阶段 -- **Info**: 一般信息,记录重要的业务流程和系统状态 -- **Warning**: 警告信息,可能的问题但不中断程序执行 -- **Error**: 错误信息,影响功能但不致命 -- **Fatal**: 致命错误,导致程序无法继续运行 - -## 框架内部日志 - -GFramework.Core 在以下关键位置自动添加了日志记录: - -### 架构模块 (Architecture) - -- 架构初始化流程 -- 组件注册和初始化 -- 生命周期阶段变更 -- 模块安装和卸载 - -### IOC容器 (IOC) - -- 对象注册和获取 -- 容器冻结操作 -- 重复注册检测 - -### 事件系统 (Event) - -- 事件发送和接收 -- 事件处理器注册和注销 - -### 系统模块 (System) - -- 系统初始化和销毁 -- 组件生命周期管理 - -## 输出格式 - -### 控制台输出示例 +**输出格式:** ``` -[2025-12-23 12:34:56.789] INFO Architecture Architecture initialized -[2025-12-23 12:34:56.790] INFO Architecture Initializing 3 systems -[2025-12-23 12:34:56.791] DEBUG Architecture Initializing system: GameSystem -[2025-12-23 12:34:56.792] INFO Architecture System registered: GameSystem -[2025-12-23 12:34:56.793] INFO Architecture Architecture is ready - all components initialized +[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**: 灰色 +- **Trace**: 深灰色 - **Debug**: 青色 - **Info**: 白色 - **Warning**: 黄色 - **Error**: 红色 - **Fatal**: 洋红色 +### [`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(); +var factory = provider.GetLoggerFactory(); +var logger = factory.GetLogger("MyApp", LogLevel.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) + { + GD.Print($"[{level}] {message}"); + if (exception != null) + GD.Print(exception); + } + } +} +``` + +## 日志级别说明 + +| 级别 | 说明 | 使用场景 | +|-------------|----------|-------------------| +| **Trace** | 最详细的跟踪信息 | 调试复杂的执行流程,记录函数调用等 | +| **Debug** | 调试信息 | 开发阶段,记录变量值、流程分支等 | +| **Info** | 一般信息 | 记录重要的业务流程和系统状态 | +| **Warning** | 警告信息 | 可能的问题但不中断程序执行 | +| **Error** | 错误信息 | 影响功能但不致命的问题 | +| **Fatal** | 致命错误 | 导致程序无法继续运行的严重错误 | + ## 最佳实践 -1. **使用合适的日志级别**: +1. **使用合适的日志级别**: - 使用 `Info` 记录重要业务流程 - 使用 `Debug` 记录调试信息 - 使用 `Warning` 记录异常情况 - 使用 `Error` 记录错误但不影响程序运行 - 使用 `Fatal` 记录严重错误 -2. **提供上下文信息**: +2. **提供上下文信息**: ```csharp - Log.Info("用户登录成功", new { UserId = userId, UserName = userName }); + logger.Info($"用户登录成功: UserId={userId}, UserName={userName}"); ``` -3. **异常日志记录**: +3. **异常日志记录**: ```csharp try { @@ -307,64 +311,45 @@ GFramework.Core 在以下关键位置自动添加了日志记录: } catch (Exception ex) { - Log.Error("数据库操作失败", ex, new { Operation = "InsertUser", UserId = userId }); + logger.Error("数据库操作失败", ex); } ``` -4. **分类使用日志**: +4. **分类使用日志**: ```csharp - var dbLogger = Log.CreateLogger("Database"); - var netLogger = Log.CreateLogger("Network"); + var dbLogger = LoggerFactoryResolver.Provider.CreateLogger("Database"); + var netLogger = LoggerFactoryResolver.Provider.CreateLogger("Network"); dbLogger.Info("查询用户数据"); netLogger.Debug("发送HTTP请求"); ``` -5. **在框架组件中合理使用日志**: +5. **在框架组件中合理使用日志**: ```csharp // 在系统初始化时记录 - protected override void OnInit() - { - Log.CreateLogger("System").Info("系统初始化完成"); - } - - // 在事件处理中记录 - architecture.RegisterEvent(evt => - { - Log.CreateLogger("Event").Info("用户登录事件", new { UserId = evt.UserId }); - }); + var logger = LoggerFactoryResolver.Provider.CreateLogger("System"); + logger.Info("系统初始化完成"); ``` -## 配置建议 +## 注意事项 -### 开发环境 +1. **日志级别检查**: + - 每个日志方法都会自动检查日志级别 + - 如果当前级别低于最小级别,不会输出日志 -```csharp -Log.Configure( - minLevel: LogLevel.Debug, - enableConsole: true, - useColors: true, - enableFile: false -); -``` +2. **格式化参数**: + - 支持字符串格式化参数 + - 支持异常信息传递 -### 生产环境 +3. **自定义比较器**: + - 在 `BindableProperty` 中可以使用 `WithComparer` 设置自定义比较器 -```csharp -var config = new LogConfig -{ - DefaultMinLevel = LogLevel.Info, - EnableConsole = false, // 生产环境通常不需要控制台输出 - UseColors = false, - EnableFile = true, - LogFilePath = "logs/production-{yyyy-MM-dd}.log" -}; +## 相关包 -config.SetCategoryLevel("Architecture", LogLevel.Info); -config.SetCategoryLevel("IOC", LogLevel.Warning); // 减少IOC日志 -config.SetCategoryLevel("Event", LogLevel.Info); +- [`architecture`](../architecture/README.md) - 架构核心,使用日志系统记录生命周期事件 +- [`property`](../property/README.md) - 可绑定属性基于事件系统实现 +- [`extensions`](../extensions/README.md) - 提供便捷的扩展方法 -Log.Initialize(config); -``` +--- -通过这个日志系统,你可以全面追踪GFramework.Core的执行过程,快速定位问题,并监控应用程序的运行状态。 \ No newline at end of file +**许可证**: Apache 2.0 diff --git a/GFramework.Core/property/README.md b/GFramework.Core/property/README.md index e9dc6f4..2f89907 100644 --- a/GFramework.Core/property/README.md +++ b/GFramework.Core/property/README.md @@ -2,7 +2,7 @@ ## 概述 -Property 包提供了可绑定属性(BindableProperty)的实现,支持属性值的监听和响应式编程。这是实现 MVVM 模式和数据绑定的核心组件。 +Property 包提供了可绑定属性(BindableProperty)的实现,支持属性值的监听和响应式编程。这是实现数据绑定和响应式编程的核心组件。 ## 核心接口 @@ -13,10 +13,17 @@ Property 包提供了可绑定属性(BindableProperty)的实现,支持属 **核心成员:** ```csharp -T Value { get; } // 获取属性值 -IUnRegister Register(Action onValueChanged); // 注册监听 -IUnRegister RegisterWithInitValue(Action action); // 注册并立即回调当前值 -void UnRegister(Action onValueChanged); // 取消监听 +// 获取属性值 +T Value { get; } + +// 注册监听(不立即触发回调) +IUnRegister Register(Action onValueChanged); + +// 注册监听并立即触发回调传递当前值 +IUnRegister RegisterWithInitValue(Action action); + +// 取消监听 +void UnRegister(Action onValueChanged); ``` ### [`IBindableProperty`](IBindableProperty.cs) @@ -26,8 +33,11 @@ void UnRegister(Action onValueChanged); // 取消监听 **核心成员:** ```csharp -new T Value { get; set; } // 可读写的属性值 -void SetValueWithoutEvent(T newValue); // 设置值但不触发事件 +// 可读写的属性值 +new T Value { get; set; } + +// 设置值但不触发事件 +void SetValueWithoutEvent(T newValue); ``` ## 核心类 @@ -42,13 +52,13 @@ void SetValueWithoutEvent(T newValue); // 设置值但不触发事件 // 创建可绑定属性 var health = new BindableProperty(100); -// 监听值变化 +// 监听值变化(不会立即触发) var unregister = health.Register(newValue => { GD.Print($"Health changed to: {newValue}"); }); -// 修改值(会触发监听器) +// 设置值(会触发监听器) health.Value = 50; // 输出: Health changed to: 50 // 取消监听 @@ -68,18 +78,26 @@ health.RegisterWithInitValue(value => // 后续值变化时也会调用 }); -// 2. 自定义比较器 +// 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认为相等 - -// 3. 链式调用 -health.Value = 100; ``` ### [`BindablePropertyUnRegister`](BindablePropertyUnRegister.cs) 可绑定属性的注销器,负责清理监听。 +**使用示例:** + +```csharp +var unregister = health.Register(OnHealthChanged); +// 当需要取消监听时 +unregister.UnRegister(); +``` + ## 在 Model 中使用 ### 定义可绑定属性 @@ -283,6 +301,26 @@ 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 层 @@ -290,10 +328,14 @@ var position = new BindableProperty() 3. **及时注销监听** - 使用 UnRegisterList 或 UnRegisterWhenNodeExitTree 4. **使用 RegisterWithInitValue** - UI 绑定时立即获取初始值 5. **避免循环依赖** - 属性监听器中修改其他属性要小心 +6. **使用自定义比较器** - 对于浮点数等需要精度控制的属性 ## 相关包 - [`model`](../model/README.md) - Model 中大量使用 BindableProperty - [`events`](../events/README.md) - BindableProperty 基于事件系统实现 -- [`controller`](../controller/README.md) - Controller 监听属性变化更新 UI -- [`extensions`](../extensions/README.md) - 提供便捷的注销扩展方法 \ No newline at end of file +- [`extensions`](../extensions/README.md) - 提供便捷的注销扩展方法 + +--- + +**许可证**: Apache 2.0 diff --git a/README.md b/README.md index 1ff506f..826cbb3 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,14 @@ # GFramework -一个专为Godot和通用游戏开发场景设计的综合性C#游戏开发框架。 +一个专为游戏开发场景设计的综合性C#游戏开发框架,Core 模块与平台无关。 本项目参考(CV)自[QFramework](https://github.com/liangxiegame/QFramework) # 为什么要有这个项目 - 原来的项目是单文件框架,我把框架拆成多个文件,方便管理 - 纯粹个人自用,要使用还是请访问[QFramework](https://github.com/liangxiegame/QFramework) -- 至于修改名字,是因为我为了方便会发布GuGet包,假设将来QFramework也要发布GuGet包,那么就会冲突了 +- 至于修改名字,是因为我为了方便会发布NuGet包,假设将来QFramework也要发布NuGet包,那么就会冲突了 +- Core 模块与 Godot 解耦,可以轻松移植到其他平台 ## 特性 Features @@ -17,95 +18,246 @@ - **事件系统 Event System**: 类型安全的事件系统,实现松耦合 - **属性绑定 Property Binding**: 可绑定属性,支持响应式编程 - **日志框架 Logging Framework**: 结构化日志,支持多个日志级别 +- **生命周期管理 Lifecycle Management**: 阶段式的架构生命周期管理 +- **命令查询分离 CQRS**: 命令和查询的职责分离 ### 游戏开发特性 Game Development Features -- **资产管理 Asset Management**: 集中化资产目录系统 +- **资产管理 Asset Management**: 集中化资产目录系统(GFramework.Game) - **资源工厂 Resource Factory**: 工厂模式的资源创建模式 - **架构模式 Architecture Pattern**: 关注点分离的清晰架构 +- **模块化 Module System**: 支持架构模块安装和扩展 -### Godot集成 Godot Integration +### 平台无关 Platform Agnostic -- **Godot特定扩展 Godot-Specific Extensions**: Godot开发的扩展和工具 -- **节点扩展 Node Extensions**: Godot节点类的有用扩展 -- **Godot日志器 Godot Logger**: Godot应用程序的专用日志系统 +- **纯 .NET 实现**: Core 模块无任何平台特定依赖 +- **Godot 集成 Godot Integration**: GFramework.Godot 提供 Godot 特定功能 +- **可移植 Portable**: 可以轻松移植到 Unity、.NET MAUI 等平台 ## 项目 Projects ### 核心项目 Core Projects -- **GFramework.Core**: 核心框架功能 -- **GFramework.Game**: 游戏特定抽象和系统 -- **GFramework.Godot**: Godot特定实现 +| 项目 | 说明 | +|----------------------------------|--------------------------------| +| **GFramework.Core** | 核心框架功能,包含架构、事件、命令、查询等(平台无关) | +| **GFramework.Core.Abstractions** | 核心接口定义 | +| **GFramework.Game** | 游戏特定抽象和系统 | +| **GFramework.Game.Abstractions** | 游戏抽象接口定义 | +| **GFramework.Godot** | Godot特定实现(Node扩展、GodotLogger等) | ### 源代码生成器 Source Generators -- **GFramework.SourceGenerators**: 自动代码生成的代码生成器 -- **GFramework.Godot.SourceGenerators**: Godot特定的代码生成器 -- **GFramework.SourceGenerators.Abstractions**: 源代码生成器的抽象 -- **GFramework.Godot.SourceGenerators.Abstractions**: Godot特定的抽象 +| 项目 | 说明 | +|---------------------------------------|---------------| +| **GFramework.SourceGenerators** | 通用源代码生成器 | +| **GFramework.Godot.SourceGenerators** | Godot特定的代码生成器 | ## 快速开始 Getting Started ### 安装 Installation -1. 安装NuGet包: - ```bash +# 安装核心包(平台无关) dotnet add package GeWuYou.GFramework.Core +dotnet add package GeWuYou.GFramework.Core.Abstractions + +# 安装游戏包 dotnet add package GeWuYou.GFramework.Game -dotnet add package GeWuYou.GFramework.SourceGenerators +dotnet add package GeWuYou.GFramework.Game.Abstractions + +# 安装Godot包(仅Godot项目需要) dotnet add package GeWuYou.GFramework.Godot -dotnet add package GeWuYou.GFramework.Godot.SourceGenerators ``` ### 基本使用 Basic Usage ```csharp -// 创建架构实例 Create an architecture instance -var architecture = new MyArchitecture(); +using GFramework.Core.architecture; -// 初始化架构 Initialize the architecture -await architecture.InitializeAsync(); +// 1. 定义架构(继承 Architecture 基类) +public class GameArchitecture : Architecture +{ + protected override void Init() + { + // 注册Model + RegisterModel(new PlayerModel()); + RegisterModel(new GameModel()); + + // 注册System + RegisterSystem(new CombatSystem()); + RegisterSystem(new UISystem()); + + // 注册Utility + RegisterUtility(new StorageUtility()); + } +} -// 访问服务 Access services -var service = architecture.Container.Resolve(); +// 2. 创建并初始化架构 +var architecture = new GameArchitecture(); +architecture.Initialize(); + +// 3. 通过依赖注入在Controller中使用 +public class PlayerController : IController +{ + private readonly IArchitecture _architecture; + + // 通过构造函数注入架构 + public PlayerController(IArchitecture architecture) + { + _architecture = architecture; + } + + public void Initialize() + { + var playerModel = _architecture.GetModel(); + + // 监听属性变化 + playerModel.Health.RegisterWithInitValue(health => + { + Console.WriteLine($"Health: {health}"); + }); + } +} ``` -### Godot集成 Godot Integration +### 命令和查询 Command & Query ```csharp -// 使用Godot特定功能 Use Godot-specific features -[GodotLog] -public partial class MyGodotNode : Node +// 定义命令 +public class AttackCommand : AbstractCommand { - // 自动生成的日志器将可用 Auto-generated logger will be available - private readonly ILogger _log = Log.GetLogger("MyGodotNode"); - - public override void _Ready() + protected override void OnExecute() { - _log.Info("Node is ready!"); + var playerModel = this.GetModel(); + var enemyModel = this.GetModel(); + + // 业务逻辑 + int damage = playerModel.AttackPower.Value; + enemyModel.Health.Value -= damage; + + // 发送事件 + this.SendEvent(new DamageDealtEvent(damage)); } } + +// 定义查询 +public class CanAttackQuery : AbstractQuery +{ + protected override bool OnDo() + { + var playerModel = this.GetModel(); + return playerModel.Health.Value > 0 && !playerModel.IsStunned.Value; + } +} + +// 使用命令和查询 +public class CombatController : IController +{ + private readonly IArchitecture _architecture; + + public CombatController(IArchitecture architecture) + { + _architecture = architecture; + } + + public void OnAttackButtonPressed() + { + // 先查询 + if (_architecture.SendQuery(new CanAttackQuery())) + { + // 再执行命令 + _architecture.SendCommand(new AttackCommand()); + } + } +} +``` + +### 事件系统 Event System + +```csharp +// 定义事件 +public struct DamageDealtEvent +{ + public int Damage; + public Vector3 Position; +} + +// 发送事件 +this.SendEvent(new DamageDealtEvent { Damage = 100, Position = position }); + +// 注册事件监听 +this.RegisterEvent(OnDamageDealt); + +private void OnDamageDealt(DamageDealtEvent e) +{ + ShowDamageNumber(e.Damage, e.Position); +} ``` ## 架构 Architecture 框架遵循清洁架构原则,具有以下层次: -1. **核心层 Core Layer**: 基础抽象和接口 Fundamental abstractions and interfaces -2. **应用层 Application Layer**: 用例和应用服务 Use cases and application services -3. **基础设施层 Infrastructure Layer**: 外部依赖和实现 External dependencies and implementations -4. **表示层 Presentation Layer**: UI和用户交互组件 UI and user interaction components +``` +┌─────────────────────────────────────────┐ +│ View / UI │ UI 层:用户界面 +├─────────────────────────────────────────┤ +│ Controller │ 控制层:处理用户输入 +├─────────────────────────────────────────┤ +│ System │ 逻辑层:业务逻辑 +├─────────────────────────────────────────┤ +│ Model │ 数据层:游戏状态 +├─────────────────────────────────────────┤ +│ Utility │ 工具层:无状态工具 +├─────────────────────────────────────────┤ +│ Command / Query │ 横切关注点 +└─────────────────────────────────────────┘ +``` + +## 生命周期 Lifecycle + +``` +初始化流程: +Init() → BeforeUtilityInit → AfterUtilityInit → BeforeModelInit → AfterModelInit → BeforeSystemInit → AfterSystemInit → Ready + +销毁流程: +Destroy() → Destroying → Destroyed +``` + +## 平台集成 Platform Integration + +### Godot 项目 + +```csharp +// 使用 GFramework.Godot 获取 Godot 特定功能 +using GFramework.Godot; + +public class GodotPlayerController : Node, IController +{ + public IArchitecture GetArchitecture() => GameArchitecture.Interface; + + public override void _Ready() + { + // 使用 Godot 特定的扩展方法 + this.RegisterEvent(OnDamageDealt) + .UnRegisterWhenNodeExitTree(this); + } +} +``` + +### 移植到其他平台 + +GFramework.Core 是纯 .NET 库,可以轻松移植到: + +- Unity(使用 Unity 容器替代 Godot 节点) +- .NET MAUI(用于跨平台 UI 应用) +- 任何其他 .NET 应用 ## 许可证 License 本项目基于Apache 2.0许可证 - 详情请参阅 [LICENSE](LICENSE) 文件。 -## 支持 Support - -如需支持和问题,请在仓库中提交问题。 - ## 框架设计理念 Framework Design Philosophy ### 核心设计原则 Core Design Principles @@ -124,17 +276,21 @@ public partial class MyGodotNode : Node - **易于测试 Easy Testing**: 依赖注入和纯函数设计 - **可扩展 Extensibility**: 基于接口的规则体系 - **生命周期管理 Lifecycle Management**: 自动的注册和注销机制 +- **平台无关 Platform Agnostic**: Core 模块可移植到任何平台 ## 技术栈 Technology Stack - **.NET 6.0+**: 跨平台运行时 -- **Godot 4.x**: 游戏引擎 - **C#**: 主要编程语言 - **Source Generators**: 源代码生成技术 +**Godot 集成**(可选): + +- **Godot 4.x**: 游戏引擎 + ## 性能特性 Performance Features - **零GC allocations**: 使用结构体和对象池减少垃圾回收 - **编译时生成**: 通过源代码生成器减少运行时开销 - **高效事件系统**: 类型安全的事件分发 -- **内存管理**: 自动生命周期管理和资源释放 \ No newline at end of file +- **内存管理**: 自动生命周期管理和资源释放