# GFramework.Core 核心框架 > 一个基于 CQRS、MVC 和事件驱动的轻量级游戏开发架构框架 ## 目录 - [框架概述](#框架概述) - [核心概念](#核心概念) - [架构图](#架构图) - [快速开始](#快速开始) - [包说明](#包说明) - [组件联动](#组件联动) - [最佳实践](#最佳实践) - [设计理念](#设计理念) ## 框架概述 本框架是一个与平台无关的轻量级架构,它结合了多种经典设计模式: - **MVC 架构模式** - 清晰的层次划分 - **CQRS 模式** - 命令查询职责分离 - **IoC/DI** - 依赖注入和控制反转 - **事件驱动** - 松耦合的组件通信 - **响应式编程** - 可绑定属性和数据流 - **阶段式生命周期管理** - 精细化的架构状态控制 **重要说明**:GFramework.Core 是与平台无关的核心模块,不包含任何 Godot 特定代码。Godot 集成功能在 GFramework.Godot 包中实现。 ### 核心特性 - **清晰的分层架构** - Model、View、Controller、System、Utility 各司其职 - **类型安全** - 基于泛型的组件获取和事件系统 - **松耦合** - 通过事件和接口实现组件解耦 - **易于测试** - 依赖注入和纯函数设计 - **可扩展** - 基于接口的规则体系 - **生命周期管理** - 自动的注册和注销机制 - **模块化** - 支持架构模块安装 - **平台无关** - Core 模块可以在任何 .NET 环境中使用 ## 核心概念 ### 五层架构 ``` ┌─────────────────────────────────────────┐ │ View / UI │ UI 层:用户界面 ├─────────────────────────────────────────┤ │ Controller │ 控制层:连接 UI 和业务逻辑 ├─────────────────────────────────────────┤ │ System │ 逻辑层:业务逻辑 ├─────────────────────────────────────────┤ │ Model │ 数据层:游戏状态 ├─────────────────────────────────────────┤ │ Utility │ 工具层:无状态工具 └─────────────────────────────────────────┘ ``` ### 横切关注点 ``` Command ──┐ Query ──┼──→ 跨层操作(修改/查询数据) Event ──┘ ``` ### 架构阶段 ``` 初始化:Init → BeforeUtilityInit → AfterUtilityInit → BeforeModelInit → AfterModelInit → BeforeSystemInit → AfterSystemInit → Ready 销毁:Destroy → Destroying → Destroyed ``` ## 架构图 ### 整体架构 ``` ┌──────────────────┐ │ Architecture │ ← 管理所有组件 └────────┬─────────┘ │ ┌────────────────────┼────────────────────┐ │ │ │ ┌───▼────┐ ┌───▼────┐ ┌───▼─────┐ │ Model │ │ System │ │ Utility │ │ 层 │ │ 层 │ │ 层 │ └───┬────┘ └───┬────┘ └────────┘ │ │ │ ┌─────────────┤ │ │ │ ┌───▼────▼───┐ ┌───▼──────┐ │ Controller │ │ Command/ │ │ 层 │ │ Query │ └─────┬──────┘ └──────────┘ │ ┌─────▼─────┐ │ View │ │ UI │ └───────────┘ ``` ### 数据流向 ``` 用户输入 → Controller → Command → System → Model → Event → Controller → View 更新 查询流程:Controller → Query → Model → 返回数据 ``` ## 快速开始 本框架采用"约定优于配置"的设计理念,只需 4 步即可搭建完整的架构。 ### 为什么需要这个框架? 在传统开发中,我们经常遇到这些问题: - 代码耦合严重:UI 直接访问游戏逻辑,逻辑直接操作 UI - 难以维护:修改一个功能需要改动多个文件 - 难以测试:业务逻辑和 UI 混在一起无法独立测试 - 难以复用:代码紧密耦合,无法在其他项目中复用 本框架通过清晰的分层解决这些问题。 ### 1. 定义架构(Architecture) **作用**:Architecture 是整个应用的"中央调度器",负责管理所有组件的生命周期。 ```csharp using GFramework.Core.Architecture; public class GameArchitecture : Architecture { protected override void Init() { // 注册 Model - 游戏数据 RegisterModel(new PlayerModel()); // 注册 System - 业务逻辑 RegisterSystem(new CombatSystem()); // 注册 Utility - 工具类 RegisterUtility(new StorageUtility()); } } ``` **优势**: - **依赖注入**:组件通过上下文获取架构引用 - **集中管理**:所有组件注册在一处,一目了然 - **生命周期管理**:自动初始化和销毁 - **平台无关**:可以在任何 .NET 环境中使用 ### 2. 定义 Model(数据层) **作用**:Model 是应用的"数据库",只负责存储和管理状态。 ```csharp public class PlayerModel : AbstractModel { // 使用 BindableProperty 实现响应式数据 public BindableProperty Health { get; } = new(100); public BindableProperty Gold { get; } = new(0); protected override void OnInit() { // Model 中可以监听自己的数据变化 Health.Register(hp => { if (hp <= 0) this.SendEvent(new PlayerDiedEvent()); }); } } // 也可以不使用 BindableProperty public class PlayerModel : AbstractModel { public int Health { get; private set; } public int Gold { get; private set; } protected override void OnInit() { Health = 100; Gold = 0; } } ``` **优势**: - **数据响应式**:BindableProperty 让数据变化自动通知监听者 - **职责单一**:只存储数据,不包含复杂业务逻辑 - **易于测试**:可以独立测试数据逻辑 ### 3. 定义 System(业务逻辑层) **作用**:System 是应用的"大脑",处理所有业务逻辑。 ```csharp public class CombatSystem : AbstractSystem { protected override void OnInit() { // System 通过事件驱动,响应游戏中的各种事件 this.RegisterEvent(OnEnemyAttack); } private void OnEnemyAttack(EnemyAttackEvent e) { var playerModel = this.GetModel(); // 处理业务逻辑:计算伤害、更新数据 playerModel.Health.Value -= e.Damage; // 发送事件通知其他组件 this.SendEvent(new PlayerTookDamageEvent { Damage = e.Damage }); } } ``` **优势**: - **事件驱动**:通过事件解耦,不同 System 之间松耦合 - **可组合**:多个 System 协同工作,每个专注自己的领域 - **易于扩展**:新增功能只需添加新的 System 和事件监听 ### 4. 定义 Controller(控制层) **作用**:Controller 是"桥梁",连接 UI 和业务逻辑。 ```csharp public class PlayerController : IController { // 通过依赖注入获取架构 private readonly IArchitecture _architecture; public PlayerController(IArchitecture architecture) { _architecture = architecture; } // 监听模型变化 public void Initialize() { var playerModel = _architecture.GetModel(); // 数据绑定:Model 数据变化自动更新 UI playerModel.Health.RegisterWithInitValue(OnHealthChanged); } private void OnHealthChanged(int hp) { // 更新 UI 显示 UpdateHealthDisplay(hp); } private void UpdateHealthDisplay(int hp) { /* UI 更新逻辑 */ } } ``` **优势**: - **自动更新 UI**:通过 BindableProperty,数据变化自动反映到界面 - **分离关注点**:UI 逻辑和业务逻辑完全分离 - **易于测试**:可以通过依赖注入模拟架构进行测试 ### 完成!现在你有了一个完整的架构 这 4 步完成后,你就拥有了: - **清晰的数据层**(Model) - **独立的业务逻辑**(System) - **灵活的控制层**(Controller) - **统一的生命周期管理**(Architecture) ### 下一步该做什么? 1. **添加 Command**:封装用户操作(如购买物品、使用技能) 2. **添加 Query**:封装数据查询(如查询背包物品数量) 3. **添加更多 System**:如任务系统、背包系统、商店系统 4. **使用 Utility**:添加工具类(如存档工具、数学工具) 5. **使用模块**:通过 IArchitectureModule 扩展架构功能 ## 包说明 | 包名 | 职责 | 文档 | |------------------|-----------------|----------------------| | **architecture** | 架构核心,管理所有组件生命周期 | [查看](./architecture) | | **constants** | 框架常量定义 | 本文档 | | **model** | 数据模型层,存储状态 | [查看](./model) | | **system** | 业务逻辑层,处理业务规则 | [查看](./system) | | **controller** | 控制器层,连接视图和逻辑 | (在 Abstractions 中) | | **utility** | 工具类层,提供无状态工具 | [查看](./utility) | | **command** | 命令模式,封装写操作 | [查看](./command) | | **query** | 查询模式,封装读操作 | [查看](./query) | | **events** | 事件系统,组件间通信 | [查看](./events) | | **property** | 可绑定属性,响应式编程 | [查看](./property) | | **ioc** | IoC 容器,依赖注入 | [查看](./ioc) | | **rule** | 规则接口,定义组件约束 | [查看](./rule) | | **extensions** | 扩展方法,简化 API 调用 | [查看](./extensions) | | **logging** | 日志系统,记录运行日志 | [查看](./logging) | | **environment** | 环境接口,提供运行环境信息 | [查看](./environment) | ## 组件联动 ### 1. 初始化流程 ``` 创建 Architecture 实例 └─> Init() ├─> RegisterModel → Model.SetContext() → Model.Init() ├─> RegisterSystem → System.SetContext() → System.Init() └─> RegisterUtility → Utility 注册到容器 ``` ### 2. Command 执行流程 ``` Controller.SendCommand(command) └─> command.Execute() └─> command.OnDo() // 子类实现 ├─> GetModel() // 获取数据 ├─> 修改 Model 数据 └─> SendEvent() // 发送事件 ``` ### 3. Event 传播流程 ``` 组件.SendEvent(event) └─> TypeEventSystem.Send(event) └─> 通知所有订阅者 ├─> Controller 响应 → 更新 UI ├─> System 响应 → 执行逻辑 └─> Model 响应 → 更新状态 ``` ### 4. BindableProperty 数据绑定 ``` Model: BindableProperty Health = new(100); Controller: Health.RegisterWithInitValue(hp => UpdateUI(hp)) 修改值: Health.Value = 50 → 触发所有回调 → 更新 UI ``` ## 最佳实践 ### 1. 分层职责原则 每一层都有明确的职责边界,遵循这些原则能让代码更清晰、更易维护。 **Model 层**: ```csharp // 好:只存储数据 public class PlayerModel : AbstractModel { public BindableProperty Health { get; } = new(100); protected override void OnInit() { } } // 坏:包含业务逻辑 public class PlayerModel : AbstractModel { public void TakeDamage(int damage) // 业务逻辑应在 System { Health.Value -= damage; if (Health.Value <= 0) Die(); } } ``` **System 层**: ```csharp // 好:处理业务逻辑 public class CombatSystem : AbstractSystem { protected override void OnInit() { this.RegisterEvent(OnAttack); } private void OnAttack(AttackEvent e) { var target = this.GetModel(); int finalDamage = CalculateDamage(e.BaseDamage, target); target.Health.Value -= finalDamage; } } ``` ### 2. 通信方式选择指南 | 通信方式 | 使用场景 | 优势 | |----------------------|-----------|----------| | **Command** | 用户操作、修改状态 | 可撤销、可记录 | | **Query** | 查询数据、检查条件 | 明确只读意图 | | **Event** | 通知其他组件 | 松耦合、可扩展 | | **BindableProperty** | 数据变化通知 | 自动化、不会遗漏 | ### 3. 生命周期管理 **为什么需要注销?** 忘记注销监听器会导致: - **内存泄漏**:对象无法被 GC 回收 - **逻辑错误**:已销毁的对象仍在响应事件 ```csharp // 使用 UnRegisterList 统一管理 private IUnRegisterList _unregisterList = new UnRegisterList(); public void Initialize() { this.RegisterEvent(OnEvent1) .AddToUnregisterList(_unregisterList); model.Property.Register(OnPropertyChanged) .AddToUnregisterList(_unregisterList); } public void Cleanup() { _unregisterList.UnRegisterAll(); } ``` ### 4. 性能优化技巧 ```csharp // 低效:每帧都查询 var model = _architecture.GetModel(); // 频繁调用 // 高效:缓存引用 private PlayerModel _playerModel; public void Initialize() { _playerModel = _architecture.GetModel(); // 只查询一次 } ``` ## 设计理念 框架的设计遵循 SOLID 原则和经典设计模式。 ### 1. 单一职责原则(SRP) - **Model**:只负责存储数据 - **System**:只负责处理业务逻辑 - **Controller**:只负责协调和输入处理 - **Utility**:只负责提供工具方法 ### 2. 开闭原则(OCP) - 通过**事件系统**添加新功能,无需修改现有代码 - 新的 System 可以监听现有事件,插入自己的逻辑 ### 3. 依赖倒置原则(DIP) - 所有组件通过接口交互 - 通过 IoC 容器注入依赖 - 易于替换实现和编写测试 ### 4. 接口隔离原则(ISP) ```csharp // 小而专注的接口 public interface ICanGetModel : IBelongToArchitecture { } public interface ICanSendCommand : IBelongToArchitecture { } public interface ICanRegisterEvent : IBelongToArchitecture { } // 组合需要的能力 public interface IController : ICanGetModel, ICanSendCommand, ICanRegisterEvent { } ``` ### 5. 组合优于继承 通过接口组合获得能力,而不是通过继承。 ### 框架核心设计模式 | 设计模式 | 应用位置 | 解决的问题 | 带来的好处 | |-----------|------------|----------|--------| | **工厂模式** | IoC 容器 | 组件的创建和管理 | 解耦创建逻辑 | | **观察者模式** | Event 系统 | 组件间的通信 | 松耦合通信 | | **命令模式** | Command | 封装操作请求 | 支持撤销重做 | | **策略模式** | System | 不同的业务逻辑 | 易于切换策略 | | **依赖注入** | 整体架构 | 组件间的依赖 | 自动管理依赖 | | **模板方法** | Abstract 类 | 定义算法骨架 | 统一流程规范 | ### 平台无关性 - **GFramework.Core**:纯 .NET 库,无任何平台特定代码 - **GFramework.Godot**:Godot 特定实现,包含 Node 扩展、GodotLogger 等 - 可以轻松将 Core 框架移植到其他平台(Unity、.NET MAUI 等) --- **版本**: 1.0.0 **许可证**: Apache 2.0