7.1 KiB
Structive Extension 架构指南
1. Extension 的职责
Structive Extension 的作用是在不修改 Core 结构模型的前提下增加领域语义解释。
推荐依赖方向:
application / adapter
↓
Structive extension
↓
Structive Property Core
Core 不 include、不 link Extension。
2. Extension 的基本模式
一个 Extension 通常只需要增加两类东西:
- 一个或多个属于自己领域的 Attribute category;
- 解释这些 Attribute 的实现代码。
如果已有 Object_Schema 已经包含需要的结构信息,就不应该再复制第二份 property registry。
3. 当前 Presentation Extension
当前扩展模块定义四个 Attribute category:
presentation::Label_Category
presentation::Description_Category
presentation::Group_Category
presentation::Order_Category
对应便利 Attribute:
presentation::label<"Temperature">
presentation::description<"Current device temperature">
presentation::group<"Environment">
presentation::order<10>
它们直接挂到普通 Core property 上:
field<&Device::temperature>(
key<"temperature">,
unit<"C">,
presentation::label<"Temperature">,
presentation::description<"Current device temperature">,
presentation::group<"Environment">,
presentation::order<10>
)
不需要 hint(...) 一类额外包装。
4. Presentation 解释
Include:
#include <structive/property/extensions/presentation.hpp>
Link:
target_link_libraries(my_target PRIVATE structive::property_extensions)
通过成员指针描述 property:
auto info = presentation::describe<&Device::temperature>(device.schema());
返回:
struct Presentation_Info {
std::string_view key;
std::string_view label;
std::string_view description;
std::string_view group;
std::size_t order;
bool has_order;
};
没有声明 presentation label 时,Presentation Extension 使用 property key 作为显示 label。这个 fallback 是 Presentation 自己的政策,不属于 Core。
5. 可继承 Extension Attribute
presentation::group 是 inheritable,因此可以放入 defaults(...):
return object<Device>(
defaults(
external_access<External_Access::read>,
presentation::group<"Environment">
),
field<&Device::temperature>(
key<"temperature">,
presentation::label<"Temperature">
),
field<&Device::pressure>(
key<"pressure">,
presentation::label<"Pressure">
)
);
Extension 通过 Core 同一套 default 机制解析有效声明。
label、description、order 不是 inheritable,因此不能放进 defaults(...)。
6. 设计一个新的 Extension Attribute
例如:
namespace my_adapter {
struct Json_Name_Category {};
template <Fixed_String Value>
struct Json_Name_Attribute {
using attribute_category = Json_Name_Category;
static constexpr bool single_valued = true;
static constexpr bool inheritable = false;
static constexpr auto value = Value;
};
template <Fixed_String Value>
inline constexpr Json_Name_Attribute<Value> json_name{};
}
在 Schema 中直接使用:
field<&Device::temperature>(
key<"temperature">,
my_adapter::json_name<"temp">
)
Core 负责存储它,但完全不需要知道 JSON 是什么。
7. 读取 Extension Attribute
单个 property descriptor:
using Property = std::remove_cvref_t<decltype(property)>;
if constexpr (Property::has_attribute<my_adapter::Json_Name_Category>) {
const auto& value = property.attribute<my_adapter::Json_Name_Category>();
}
可继承 category 使用 effective declared lookup:
if constexpr (has_declared_effective_attribute_v<Schema, Index, My_Category>) {
const auto& value = declared_effective_attribute<Index, My_Category>(schema);
}
它先检查 property declaration,再检查 object defaults。
8. Multi-Valued Metadata
Core 的唯一性由 category 协议决定。拥有非 void attribute_category 且 single_valued = true 的 Attribute,在同一个声明中只能出现一次。
如果某个领域天然需要重复 annotation,就不要错误地宣称它是 single-valued category;可以通过 for_each_attribute(...) 遍历并消费多项数据。
不要为了满足 single-valued 设计,把本来可以重复的独立元数据硬塞进一个巨大对象。
9. 合理的未来 Extension 边界
未来 Extension 可以合理拥有例如:
- serialization name / omission policy;
- RPC exposure rule;
- UI label / group / editor hint;
- database column mapping;
- configuration-file mapping;
- domain documentation generation。
这些只是合理领域示例,不代表当前已经实现。
关键边界是 Core 不能因此直接依赖这些领域库或类型。
10. Extension 可以消费 Core Metadata
Extension 可以读取 Core-owned category,只要这些 category 本来就是它的输入契约。
例如 External Adapter 可以使用:
- property
key作为默认协议名字; External_Access判断是否暴露;sensitive决定自己的日志是否隐藏值。
Extension 可以基于这些信息建立自己领域的政策,但不能改变 Core 对这些 Attribute 的基础含义。
11. Fallback 行为属于 Consumer
Presentation Extension 当前就是示范:
没有 label Attribute
↓
Presentation Extension 使用 property key 作为 label
Core 不应该发明这个 fallback,因为另一个 consumer 完全可能需要另一种策略。
未来 Adapter 也应该遵守这个原则。只为了某个领域“好用”的默认逻辑应该留在那个领域内部。
12. 防止 Extension 语义泄漏进 Core
错误方向:
JSON Adapter 需要 alias
↓
Core 增加 JSON_Alias_Category 和 JSON 命名逻辑
正确方向:
JSON Extension 定义 Json_Name_Category
↓
JSON Extension 自己解释
↓
Core 保持领域中立
13. Header-Only Metadata 与 Linked Implementation
Attribute 定义通常可以 header-only。具体解释逻辑可以根据实现需要选择 header-only 或 linked。
当前 Presentation Extension 使用 linked target:presentation::describe() 在模板层完成 Attribute 选择,然后调用链接实现 make_presentation_info() 生成最终结果并处理 fallback。
不能因为扩展代码量小,就把它的 linked implementation 搬进 Core。
14. Extension 审核清单
新增 Extension 功能前检查:
- 这个概念属于 Core,还是只属于某个 consumer domain?
- 能否直接使用现有 Attribute 协议表达?
- Extension 是否拥有自己解释的 category?
- Inheritable Attribute 是否真的属于对象级默认政策?
- Fallback 是否保留在 Extension 内?
- 是否复用已有 Schema,而不是复制结构树?
- 依赖是否仍然从 Extension 指向 Core?
- Core 是否仍然没有第三方领域类型?
- Extension 是否保持了 Core access、validation、synchronization 的原有语义?
如果依赖方向或语义边界不成立,应先重新设计分层,再写代码。