mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-23 03:04:29 +08:00
- 添加 Initialize() 和 InitializeAsync() 方法的详细文档 - 补充 InstallModule 模块管理和 RegisterLifecycleHook 生命周期钩子说明 - 增加 CurrentPhase 和 Context 属性的使用示例 - 提供完整的代码示例和异常处理说明
508 lines
16 KiB
Markdown
508 lines
16 KiB
Markdown
# 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 │ 控制层:处理用户输入
|
||
├─────────────────────────────────────────┤
|
||
│ 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<int> Health { get; } = new(100);
|
||
public BindableProperty<int> 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<EnemyAttackEvent>(OnEnemyAttack);
|
||
}
|
||
|
||
private void OnEnemyAttack(EnemyAttackEvent e)
|
||
{
|
||
var playerModel = this.GetModel<PlayerModel>();
|
||
|
||
// 处理业务逻辑:计算伤害、更新数据
|
||
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<PlayerModel>();
|
||
|
||
// 数据绑定: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/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 实例
|
||
└─> Init()
|
||
├─> RegisterModel → Model.SetContext() → Model.Init()
|
||
├─> RegisterSystem → System.SetContext() → System.Init()
|
||
└─> RegisterUtility → Utility 注册到容器
|
||
```
|
||
|
||
### 2. Command 执行流程
|
||
|
||
```
|
||
Controller.SendCommand(command)
|
||
└─> command.Execute()
|
||
└─> command.OnDo() // 子类实现
|
||
├─> GetModel<T>() // 获取数据
|
||
├─> 修改 Model 数据
|
||
└─> SendEvent() // 发送事件
|
||
```
|
||
|
||
### 3. Event 传播流程
|
||
|
||
```
|
||
组件.SendEvent(event)
|
||
└─> TypeEventSystem.Send(event)
|
||
└─> 通知所有订阅者
|
||
├─> Controller 响应 → 更新 UI
|
||
├─> System 响应 → 执行逻辑
|
||
└─> Model 响应 → 更新状态
|
||
```
|
||
|
||
### 4. BindableProperty 数据绑定
|
||
|
||
```
|
||
Model: BindableProperty<int> Health = new(100);
|
||
Controller: Health.RegisterWithInitValue(hp => UpdateUI(hp))
|
||
修改值: Health.Value = 50 → 触发所有回调 → 更新 UI
|
||
```
|
||
|
||
## 最佳实践
|
||
|
||
### 1. 分层职责原则
|
||
|
||
每一层都有明确的职责边界,遵循这些原则能让代码更清晰、更易维护。
|
||
|
||
**Model 层**:
|
||
|
||
```csharp
|
||
// 好:只存储数据
|
||
public class PlayerModel : AbstractModel
|
||
{
|
||
public BindableProperty<int> 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<AttackEvent>(OnAttack);
|
||
}
|
||
|
||
private void OnAttack(AttackEvent e)
|
||
{
|
||
var target = this.GetModel<PlayerModel>();
|
||
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<Event1>(OnEvent1)
|
||
.AddToUnregisterList(_unregisterList);
|
||
|
||
model.Property.Register(OnPropertyChanged)
|
||
.AddToUnregisterList(_unregisterList);
|
||
}
|
||
|
||
public void Cleanup()
|
||
{
|
||
_unregisterList.UnRegisterAll();
|
||
}
|
||
```
|
||
|
||
### 4. 性能优化技巧
|
||
|
||
```csharp
|
||
// 低效:每帧都查询
|
||
var model = _architecture.GetModel<PlayerModel>(); // 频繁调用
|
||
|
||
// 高效:缓存引用
|
||
private PlayerModel _playerModel;
|
||
|
||
public void Initialize()
|
||
{
|
||
_playerModel = _architecture.GetModel<PlayerModel>(); // 只查询一次
|
||
}
|
||
```
|
||
|
||
## 设计理念
|
||
|
||
框架的设计遵循 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
|