4.6 KiB
4.6 KiB
项目约定规范(接口层 / 实现层)
what every programmer should know about memory
本文档用于统一本项目在 EngineAPI、Components、Platform、Utilities 等目录下的设计与编码约定,重点规范“接口层与实现层分离”。
1. 分层职责约定
1.1 EngineAPI 层(对外契约层)
- 只暴露稳定接口:强类型 ID、句柄类、对外可调用的 API。
- 不暴露内部容器与存储细节,不暴露运行时池结构。
- 允许声明行为,不实现复杂运行逻辑。
- 头文件应可被上层模块直接 include,尽量减少内部依赖。
示例:
Engine/EngineAPI/ScriptComponent.h:仅定义script_id与script::component句柄。
1.2 Components 层(运行时实现层)
- 实现组件生命周期:
create/remove/update。 - 管理内部存储:数组、映射、空闲队列、代数校验。
- 对外只通过 API 层句柄交互,不向外泄露内部布局。
- 允许高性能实现细节(如
erase_unordered、缓存表、延迟提交)。
示例:
Engine/Components/Script.h/.cpp:实现脚本创建、删除、逐帧更新和注册表逻辑。
1.3 Platform 层(平台适配层)
- 只处理操作系统相关对象与流程(如 Win32
HWND、消息循环、窗口样式)。 - 上层通过抽象类型访问,不直接依赖平台原生类型。
- 平台特有分支必须受平台宏保护(如
_WIN64)。
1.4 Utilities 层(通用基础层)
- 提供与业务无关的数学、容器、IO、工具函数。
- 不耦合具体业务组件,不反向依赖高层模块。
2. 文件组织约定
2.1 命名与位置
- 对外契约放
EngineAPI,运行时实现放Components。 - 头文件与实现文件成对组织:
Xxx.h/Xxx.cpp。 - 公共依赖入口统一放在模块公共头(如
ComponentsCommon.h)。
2.2 include 方向
- 允许
Components -> EngineAPI依赖。 - 禁止
EngineAPI -> Components反向依赖实现细节。 Utilities不应依赖Components或Platform。
2.3 前向声明优先
- 能前向声明时不直接 include 重头文件。
- 对外头文件避免引入不必要实现依赖,控制编译扇出。
3. 类型与句柄约定
3.1 强类型 ID
- 所有核心对象 ID 使用强类型封装(
DEFINE_TYPED_ID)。 - 禁止在模块边界裸传
u32作为对象标识。 - 必须通过
is_valid/generation做有效性校验。
3.2 句柄对象
- 对外使用轻量句柄(如
script::component、game_entity::entity)。 - 句柄仅保存 ID,不保存大对象数据。
- 句柄方法可转发到实现层查询真实数据。
4. 生命周期与存储约定
4.1 创建与删除
create负责分配 ID、构造实例、建立映射。remove必须清理映射、回收槽位、更新空闲队列。- 必须保证删除后旧句柄不可通过代数校验。
4.2 映射一致性
- 使用
id_mapping时必须保证:id -> 索引映射存在且越界受保护;- 交换删除后映射及时回填;
- 无效 ID 显式写回
invalid_id。
4.3 批处理更新
- 高频写入优先使用缓存并批量提交(如脚本修改 Transform 后统一提交)。
- 帧内缓存必须在提交后清空,避免跨帧污染。
5. 脚本系统专项约定
5.1 注册机制
- 脚本类型通过统一宏注册(
REGISTER_SCRIPT(TYPE))。 - 注册信息至少包含:类型名哈希、工厂函数指针。
- 编辑器模式下可额外导出脚本名列表。
5.2 工厂机制
- 统一使用
script_creator创建脚本实例。 - 禁止外部直接 new 并绕过组件创建流程。
- 工厂函数签名保持稳定,避免跨模块 ABI 漂移。
6. 注释与文档约定
6.1 文件头注释
- 使用
@file+@brief+@details。 @details需说明职责边界、数据流、关键约束。
6.2 函数注释
- 对核心函数标注参数、返回值、副作用。
- 对平台参数表、结构体字段允许保留逐行行尾注释。
- 禁止乱码注释;统一 UTF-8 编码保存。
7. 可维护性与扩展性约定
- 先保证接口稳定,再演进实现细节。
- 扩展新组件时,优先复用现有 ID/句柄/生命周期模式。
- 变更跨层关系时必须先更新本规范文档与对应模块分析文档。
8. 变更检查清单(提交前)
- 是否保持
EngineAPI与Components的边界不反转。 - 是否新增了不必要 include 或扩大了依赖扇出。
- 是否破坏了 ID 代数校验与映射一致性。
- 是否补齐了注释并确保无乱码。
- 是否与现有目录结构与命名风格一致。