2026-03-21 15:56:18 +08:00

22 KiB
Raw Permalink Blame History

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   ──┘

架构阶段

框架提供了精细化的生命周期管理,包含 11 个阶段:

初始化流程:
None → BeforeUtilityInit → AfterUtilityInit → BeforeModelInit → AfterModelInit → BeforeSystemInit → AfterSystemInit → Ready

销毁流程:
Ready → Destroying → Destroyed

异常流程:
Any → FailedInitialization

每个阶段都会触发 PhaseChanged 事件,允许组件监听架构状态变化。

架构图

整体架构

从 v1.1.0 开始,Architecture 类采用模块化设计,将职责分离到专门的管理器中:

                     ┌──────────────────┐
                     │   Architecture   │ ← 核心协调器
                     └────────┬─────────┘
                              │
         ┌────────────────────┼────────────────────┐
         │                    │                    │
    ┌────▼────────┐   ┌──────▼──────┐   ┌────────▼────────┐
    │ Lifecycle   │   │ Component   │   │    Modules      │
    │  Manager    │   │  Registry   │   │    Manager      │
    └─────────────┘   └─────────────┘   └─────────────────┘
         │                    │                    │
         │                    │                    │
    生命周期管理          组件注册管理            模块管理
    - 阶段转换            - System 注册          - 模块安装
    - 钩子管理            - Model 注册           - 行为注册
    - 初始化/销毁         - Utility 注册

这种设计遵循单一职责原则,使代码更易维护和测试。

                     ┌──────────────────┐
                     │   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 是整个应用的"中央调度器",负责管理所有组件的生命周期。

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 是应用的"数据库",只负责存储和管理状态。

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 是应用的"大脑",处理所有业务逻辑。

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 和业务逻辑。

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 内部结构 (v1.1.0+)

从 v1.1.0 开始,Architecture 类采用模块化设计,将原本 708 行的单一类拆分为 4 个职责清晰的类:

1. Architecture (核心协调器)

职责: 提供统一的公共 API,协调各个管理器

主要方法:

  • RegisterSystem<T>() - 注册系统
  • RegisterModel<T>() - 注册模型
  • RegisterUtility<T>() - 注册工具
  • InstallModule() - 安装模块
  • InitializeAsync() / Initialize() - 初始化架构
  • DestroyAsync() / Destroy() - 销毁架构

事件:

  • PhaseChanged - 阶段变更事件

2. ArchitectureLifecycle (生命周期管理器)

职责: 管理架构的生命周期和阶段转换

核心功能:

  • 11 个架构阶段的管理和转换
  • 生命周期钩子 (IArchitectureLifecycleHook) 管理
  • 组件初始化 (按 Utility → Model → System 顺序)
  • 组件销毁 (逆序销毁)
  • 就绪状态管理

关键方法:

  • EnterPhase() - 进入指定阶段
  • RegisterLifecycleHook() - 注册生命周期钩子
  • InitializeAllComponentsAsync() - 初始化所有组件
  • DestroyAsync() - 异步销毁

3. ArchitectureComponentRegistry (组件注册管理器)

职责: 管理 System、Model、Utility 的注册

核心功能:

  • 组件注册和验证
  • 自动设置组件上下文 (IContextAware)
  • 自动注册组件生命周期 (IInitializable、IDestroyable)
  • 支持实例注册和类型注册

关键方法:

  • RegisterSystem<T>() - 注册系统
  • RegisterModel<T>() - 注册模型
  • RegisterUtility<T>() - 注册工具

4. ArchitectureModules (模块管理器)

职责: 管理架构模块和中介行为

核心功能:

  • 模块安装 (IArchitectureModule)
  • 中介行为注册 (Mediator Behaviors)

关键方法:

  • InstallModule() - 安装模块
  • RegisterMediatorBehavior<T>() - 注册中介行为

设计优势

这种模块化设计带来以下优势:

  1. 单一职责: 每个类只负责一个明确的功能
  2. 易于测试: 可以独立测试每个管理器
  3. 易于维护: 修改某个功能不影响其他功能
  4. 易于扩展: 添加新功能更容易
  5. 代码安全: 消除了 null! 断言,所有字段在构造后立即可用

详细的设计决策已在架构实现重构中落地。


包说明

包名 职责 文档
architecture 架构核心,管理所有组件生命周期 查看
constants 框架常量定义 本文档
model 数据模型层,存储状态 查看
system 业务逻辑层,处理业务规则 查看
controller 控制器层,连接视图和逻辑 (在 Abstractions 中)
utility 工具类层,提供无状态工具 查看
command 命令模式,封装写操作 查看
query 查询模式,封装读操作 查看
events 事件系统,组件间通信 查看
property 可绑定属性,响应式编程 查看
ioc IoC 容器,依赖注入 查看
rule 规则接口,定义组件约束 查看
extensions 扩展方法,简化 API 调用 查看
logging 日志系统,记录运行日志 查看
environment 环境接口,提供运行环境信息 查看
localization 本地化系统,多语言支持 查看

组件联动

1. 初始化流程

创建 Architecture 实例
    └─> 构造函数
        ├─> 初始化 Logger
        ├─> 创建 ArchitectureLifecycle
        ├─> 创建 ArchitectureComponentRegistry
        └─> 创建 ArchitectureModules
    └─> InitializeAsync()
        ├─> OnInitialize() (用户注册组件)
        │   ├─> RegisterModel → Model.SetContext()
        │   ├─> RegisterSystem → System.SetContext()
        │   └─> RegisterUtility → 注册到容器
        └─> InitializeAllComponentsAsync()
            ├─> BeforeUtilityInit → Utility.Initialize()
            ├─> BeforeModelInit → Model.Initialize()
            ├─> BeforeSystemInit → System.Initialize()
            └─> Ready

重要变更 (v1.1.0): 管理器现在在构造函数中初始化,而不是在 InitializeAsync 中。这消除了 null! 断言,提高了代码安全性。

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 层

// 好:只存储数据
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 层

// 好:处理业务逻辑
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 回收
  • 逻辑错误:已销毁的对象仍在响应事件
// 使用 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. 性能优化技巧

// 低效:每帧都查询
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

// 小而专注的接口
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.GodotGodot 特定实现,包含 Node 扩展、GodotLogger 等
  • 可以轻松将 Core 框架移植到其他平台Unity、.NET MAUI 等)

版本: 1.1.0 更新日期: 2026-03-17 许可证: Apache 2.0

更新日志

v1.1.0 (2026-03-17)

重大重构:

  • 拆分 Architecture 类为 4 个职责清晰的类
  • 消除 3 处 null! 强制断言,提高代码安全性
  • 在构造函数中初始化管理器,符合"构造即完整"原则
  • 添加 PhaseChanged 事件,支持阶段监听

向后兼容: 所有公共 API 保持不变,现有代码无需修改。