去除所有访问级别
This commit is contained in:
+264
-305
@@ -4,434 +4,393 @@
|
||||
|
||||
## 1. 设计目标
|
||||
|
||||
Structive 的目标是给普通 C++ 对象增加一层机器可理解的结构语义,同时不强迫业务对象改用框架自己的存储模型。
|
||||
Structive 的目标是在保留 C++ 原生对象模型的前提下,为普通 struct 增加显式结构语义。
|
||||
|
||||
它应该能够回答:
|
||||
它不是第二套语言、反射运行时、安全边界、ORM 或对象框架。它是一层尽可能贴近普通 C++ 的结构元数据和 managed property 能力。
|
||||
|
||||
- 哪些成员属于公开结构模型?
|
||||
- 某个属性稳定的 runtime key 是什么?
|
||||
- 哪些属性允许外部读取或写入?
|
||||
- 哪些属性参与持久化?
|
||||
- 哪些元数据属于 Presentation、Validation 或其他扩展?
|
||||
- 哪些属性位于同一个同步域?
|
||||
- 动态适配器如何在遵守 capability 的前提下读写属性?
|
||||
目标模型:
|
||||
|
||||
但完成这些事情以后,底层类型仍然应该看起来像正常的 C++。
|
||||
```text
|
||||
普通 C++ 数据
|
||||
+ 显式 Schema
|
||||
+ Property 固有能力
|
||||
+ Metadata
|
||||
+ 可选 Managed Synchronization
|
||||
+ 可选 Runtime Adapter
|
||||
```
|
||||
|
||||
## 2. 第一原则:增强,而不是替代
|
||||
|
||||
Structive 不是第二套对象模型,而是附加在已有 C++ 类型旁边的结构层。
|
||||
第一原则:
|
||||
|
||||
推荐形态:
|
||||
> **增强 struct,而不是替代 struct。**
|
||||
|
||||
```cpp
|
||||
struct Device : structive::Property_Object<Device> {
|
||||
double temperature;
|
||||
std::string name;
|
||||
};
|
||||
```
|
||||
注册字段仍是真实 C++ 成员。未注册状态仍然是普通 C++。只要 C++ 类型本身允许,raw access 永远存在。
|
||||
|
||||
而不是:
|
||||
Structive 不要求每个字段变成 `Property<T>`,也不应该迫使业务对象进入第二套对象模型。
|
||||
|
||||
```cpp
|
||||
struct Device {
|
||||
Framework_Property<double> temperature;
|
||||
Framework_Property<std::string> name;
|
||||
};
|
||||
```
|
||||
### 原则
|
||||
|
||||
这个原则保护了原生 C++ 的几个关键性质:
|
||||
如果一个能力可以通过 metadata 或很薄的 managed layer 实现,就不要改变原生 member model。
|
||||
|
||||
1. 成员仍然是真实成员。
|
||||
2. 成员指针仍然可以作为可靠身份。
|
||||
3. 所有权规则允许时仍然可以 raw access。
|
||||
4. 未注册成员可以继续作为实现细节存在。
|
||||
5. Structive 元数据可以和存储形式独立演进。
|
||||
## 3. 类型信息与实例行为必须分层
|
||||
|
||||
这个原则也有明确代价:Structive 不可能拦截直接成员访问。只有通过 managed path 的访问才会获得 Structive 管理行为。
|
||||
|
||||
## 3. 必须保持两层,而不是揉成一层
|
||||
|
||||
Structive 把类型级描述和实例级管理分开。
|
||||
Structive 有两层架构。
|
||||
|
||||
### 3.1 类型层
|
||||
|
||||
`Type_Descriptor<T>` 产生 `Object_Schema`,描述:
|
||||
`Type_Descriptor<T>` 与 `Object_Schema` 保存结构事实:
|
||||
|
||||
- 注册属性;
|
||||
- 属性 key;
|
||||
- accessor;
|
||||
- 注册 Property;
|
||||
- key;
|
||||
- intrinsic readable/writable;
|
||||
- Attribute;
|
||||
- constraint;
|
||||
- object 级可继承默认值;
|
||||
- 默认 synchronization plan。
|
||||
- Constraint;
|
||||
- 默认 synchronization 描述。
|
||||
|
||||
这是类型的结构定义。
|
||||
这些属于类型。
|
||||
|
||||
### 3.2 实例层
|
||||
|
||||
`Property_Object<T>` 提供:
|
||||
`Property_Object<T>` 提供实例行为:
|
||||
|
||||
- 同一类型共享的默认解析 lock slot 拓扑;
|
||||
- 只有真实锁策略才需要的每实例 mutex 存储;
|
||||
- 只有显式同步覆盖实例才持有的紧凑 topology;
|
||||
- managed typed read/write;
|
||||
- capability view;
|
||||
- 静态与运行时多属性 guard;
|
||||
- managed value traversal;
|
||||
- `Property_Object_Base` type-erased runtime access。
|
||||
- managed read/write;
|
||||
- 可写同步域所需的锁存储;
|
||||
- 多属性 Guard;
|
||||
- traversal;
|
||||
- type-erased runtime access;
|
||||
- 可选的每实例 synchronization override。
|
||||
|
||||
这是实例行为,不是 Schema 身份。
|
||||
### 原则
|
||||
|
||||
### 3.3 设计约束
|
||||
|
||||
不要把可变的实例同步状态塞进 Schema,也不要让 Schema 必须依赖某一种特定的实例管理策略。由类型级默认同步计划推导出的不可变 topology 可以由同类型所有实例共享。
|
||||
|
||||
以后完全可能有用户只想描述大量普通对象,却不愿意为每个对象承担同步状态成本。当前架构应该持续保留这种可能性。
|
||||
除非信息真的随实例变化,否则不要把类型级事实复制到每个对象里。
|
||||
|
||||
## 4. 注册必须显式
|
||||
|
||||
Structive 不认为所有 C++ 成员都天然属于结构模型。
|
||||
Structive 不假设所有成员都是 Property。
|
||||
|
||||
```cpp
|
||||
struct Device : structive::Property_Object<Device> {
|
||||
int id;
|
||||
double temperature;
|
||||
mutable int internal_cache;
|
||||
struct Device : Property_Object<Device> {
|
||||
int temperature;
|
||||
int internal_cache;
|
||||
};
|
||||
```
|
||||
|
||||
如果 Schema 只注册 `id` 和 `temperature`,那么 `internal_cache` 对 Structive 完全不可见。
|
||||
|
||||
这是故意的。结构暴露本身就是 API 设计,不应该根据物理布局自动推断。
|
||||
只注册 `temperature` 时,`internal_cache` 完全不属于 Structive Schema。
|
||||
|
||||
### 原则
|
||||
|
||||
**Schema 才是公开结构契约;struct 的物理成员集合不是自动 Schema。**
|
||||
注册决定参与;不在 Schema 中就不属于 Structive。
|
||||
|
||||
## 5. C++ 内部优先使用编译期身份
|
||||
## 5. Intrinsic Capability 属于 Property 自己
|
||||
|
||||
业务 C++ 代码通常应该通过成员指针定位 member-backed property:
|
||||
Structive **没有内建访问控制系统**。
|
||||
|
||||
```cpp
|
||||
device.read<&Device::temperature>();
|
||||
device.write<&Device::temperature>(30.0);
|
||||
device.schema().property<&Device::temperature>();
|
||||
```
|
||||
|
||||
这样编译器能够建立最强的“对象类型—字段”关系。
|
||||
|
||||
数字 index 适合编译期泛型遍历;字符串 key 适合运行时边界。
|
||||
|
||||
### 身份层级
|
||||
Property 只描述自己固有支持什么:
|
||||
|
||||
```text
|
||||
业务 C++ 代码 → member pointer
|
||||
编译期泛型代码 → property index
|
||||
runtime / adapter → declared string key
|
||||
none
|
||||
read
|
||||
write
|
||||
read_write
|
||||
```
|
||||
|
||||
不要因为存在 key,就把本来可以静态确定的 C++ 业务代码全部字符串化。
|
||||
|
||||
## 6. Key 是结构协议标识,不是显示名称
|
||||
|
||||
每个 `Property_Descriptor` 都必须拥有非空 `key`,同一 Schema 内 key 必须唯一。
|
||||
|
||||
Key 被 Schema lookup、动态锁选择、runtime read/write 使用。因此它不只是 UI label。
|
||||
|
||||
即使 C++ 成员名不变,修改 key 也可能改变外部协议或持久化契约。
|
||||
|
||||
### 原则
|
||||
|
||||
**把 property key 当成协议级名字,重命名必须有意识。**
|
||||
|
||||
## 7. 只有一套 Attribute 系统
|
||||
|
||||
Structive 不应该再长出 `hint`、`annotation`、`ui metadata`、`serializer metadata` 等彼此独立的元数据容器。
|
||||
|
||||
一个 Attribute 可以声明:
|
||||
|
||||
- `attribute_category`:用于按 category 查询;
|
||||
- `single_valued`:同一个声明中该 category 是否只能有一个值;
|
||||
- `inheritable`:是否允许进入 object defaults;
|
||||
- category 自己需要的 payload。
|
||||
|
||||
Core 和 Extension 使用完全相同的协议。
|
||||
|
||||
### 原则
|
||||
|
||||
**增加语义时优先增加 Attribute category + interpreter,而不是再造一套 metadata framework。**
|
||||
|
||||
## 8. Category 必须有明确所有者
|
||||
|
||||
Core 只解释属于 Core 的 category。
|
||||
|
||||
例如 External Access 和 Persistence Access 会直接影响 Core capability view,所以 Core 理解它们是合理的;但 Core 不需要理解 `presentation::label`。
|
||||
|
||||
Presentation 解释 Presentation;未来 JSON 扩展解释 JSON;RPC 扩展解释 RPC。
|
||||
|
||||
Core 只负责统一保存、遍历和提供查询机制。
|
||||
|
||||
### 依赖约束
|
||||
|
||||
```text
|
||||
Extension implementation
|
||||
↓
|
||||
Structive Property Core
|
||||
```
|
||||
|
||||
不能为了某个扩展写起来方便,就反过来让 Core 依赖 Extension。
|
||||
|
||||
## 9. Defaults 是继承,不是隐藏行为
|
||||
|
||||
`defaults(...)` 用于支持可继承 Attribute。Property 级声明仍然可以覆盖同 category 的默认值。
|
||||
|
||||
当前 Core 中可继承的 category 包括 External Access、Persistence Access 和 Sensitive。
|
||||
|
||||
Defaults 应该用于稳定的对象级政策默认值,而不是用来制造大量隐式行为。
|
||||
|
||||
### 原则
|
||||
|
||||
**Defaults 用来减少重复,但不能让一个属性最终生效的政策变得无法从 Schema 规则中推导。**
|
||||
|
||||
## 10. Managed Access 与 Raw Access 是两种契约
|
||||
|
||||
Raw access:
|
||||
通常由 Accessor 自动推导,也可以通过 metadata 显式收窄。
|
||||
|
||||
```cpp
|
||||
device.temperature = 30.0;
|
||||
field<&Device::serial_number>(key<"serial_number">, read_only)
|
||||
```
|
||||
|
||||
Managed access:
|
||||
它表达:
|
||||
|
||||
```cpp
|
||||
device.write<&Device::temperature>(30.0);
|
||||
```
|
||||
> 在 Structive managed model 中,这个属性可读、不可写。
|
||||
|
||||
Raw path 就是普通 C++,不会自动获得 Structive 锁和 capability 管理。
|
||||
|
||||
Managed path 会经过 descriptor 和该实例的同步拓扑。
|
||||
|
||||
两条路径同时存在是设计结果,不是漏洞。
|
||||
它不表达哪个用户、服务、GUI 或进程有权限看到它。
|
||||
|
||||
### 原则
|
||||
|
||||
不要假装继承 `Property_Object<T>` 以后 public member 就自动变成强封装属性。如果某个子系统要求受管理同步,那么该子系统自己的编码约束必须要求使用 managed path。
|
||||
Property capability 描述结构,不描述授权。
|
||||
|
||||
## 11. 固有能力先于边界投影
|
||||
## 6. Core 不拥有外部访问策略
|
||||
|
||||
每个 Property 首先拥有 accessor 自身决定的能力:
|
||||
Structive 不定义下面这些 managed access mode:
|
||||
|
||||
```text
|
||||
intrinsic
|
||||
├── read
|
||||
└── write
|
||||
internal
|
||||
external
|
||||
persistence
|
||||
role
|
||||
context
|
||||
permission
|
||||
```
|
||||
|
||||
应用内部的普通 managed code 通过 `read()`、`write()`、lock 和 traversal 直接使用这套固有能力,因此 `internal` 不再是单独的 capability mode。
|
||||
GUI 自己决定哪些属性可编辑,RPC 自己决定暴露哪些字段,持久化系统自己决定保存哪些字段。
|
||||
|
||||
External 和 Persistence 是同一份 Property definition 之上的边界投影:
|
||||
|
||||
```text
|
||||
Property
|
||||
├── intrinsic: read / write
|
||||
├── external: read / write projection
|
||||
└── persistence: load / store projection
|
||||
```
|
||||
|
||||
Core 会把投影 Attribute 与 accessor 的实际能力结合起来。投影可以收窄固有能力,但绝不能凭空创造 accessor 本身不具备的能力。
|
||||
|
||||
External view 不应该发展成第二份 Schema;Persistence view 也不应该成为第二份 Schema。它们都只是同一 Schema 的能力投影。
|
||||
Core 只提供结构事实,Consumer 自己定义策略。
|
||||
|
||||
### 原则
|
||||
|
||||
**一份 property definition,固有能力明确,边界投影显式。**
|
||||
不要因为某个 Adapter 需要策略,就把这个策略塞进 Core。
|
||||
|
||||
## 12. Validation = 元数据 + 显式操作
|
||||
## 7. Raw Access 与 Managed Access 是两种契约
|
||||
|
||||
Constraint 描述候选值是否合法,但 `write()` 不会自动执行它。
|
||||
|
||||
必须保持分开的概念包括:
|
||||
|
||||
```text
|
||||
单字段 constraint
|
||||
跨字段 invariant
|
||||
locking
|
||||
transaction boundary
|
||||
rollback strategy
|
||||
error reporting
|
||||
side effects
|
||||
```
|
||||
|
||||
一个通用 `write()` 不可能替所有业务正确猜出这些规则。
|
||||
|
||||
### 示例
|
||||
下面两句故意具有不同语义:
|
||||
|
||||
```cpp
|
||||
auto guard = device.lock_unique<&Device::min_speed, &Device::max_speed>();
|
||||
auto old_min = guard.get<&Device::min_speed>();
|
||||
auto old_max = guard.get<&Device::max_speed>();
|
||||
guard.set<&Device::min_speed>(candidate_min);
|
||||
guard.set<&Device::max_speed>(candidate_max);
|
||||
if (candidate_min > candidate_max) {
|
||||
guard.set<&Device::min_speed>(old_min);
|
||||
guard.set<&Device::max_speed>(old_max);
|
||||
}
|
||||
device.temperature = 30;
|
||||
device.write<&Device::temperature>(30);
|
||||
```
|
||||
|
||||
业务操作自己拥有 invariant 和 rollback 语义。
|
||||
Raw path 遵守普通 C++。Managed path 遵守 Structive Schema 与同步模型。
|
||||
|
||||
如果代码直接写一个 `read_only` public member,它就是主动绕过 Structive contract。
|
||||
|
||||
### 原则
|
||||
|
||||
**不要把 `write()` 变成隐藏事务引擎。**
|
||||
Structive 服务于遵守 managed contract 的代码,不假装能阻止故意绕过系统的 raw C++。
|
||||
|
||||
## 13. Synchronization 就只负责 Synchronization
|
||||
## 8. Read-Only Metadata 必须产生真实优化
|
||||
|
||||
Synchronization plan 的本质是把 property 映射到 lock slot,支持 independent、shared、unsynchronized、grouped 等配置。
|
||||
如果一个存储属性无法通过 Structive 被写入,那么不存在另一个 Structive managed writer 与它竞争。
|
||||
|
||||
Group 表示一致性域:同一个 group 的 property 使用同一个 mutex slot。
|
||||
因此 intrinsic read-only 的存储属性:
|
||||
|
||||
多属性锁会对 slot 去重,并按稳定 slot 顺序获取锁。
|
||||
- 不分配 lock slot;
|
||||
- 不贡献 mutex;
|
||||
- 不受宽泛默认同步模式影响;
|
||||
- managed read 不查询 lock slot;
|
||||
- managed read 不构造 `shared_lock`。
|
||||
|
||||
### Synchronization 不等于
|
||||
这是 Schema 信息直接产生的结构优化。
|
||||
|
||||
- validation;
|
||||
- transaction;
|
||||
- rollback;
|
||||
- event emission;
|
||||
- dirty tracking;
|
||||
- persistence commit。
|
||||
### 原则
|
||||
|
||||
这些能力可以构建在 Structive 上层,但不能偷偷和锁耦合。
|
||||
如果 Schema 已经证明某项运行时状态没有必要,就不要分配,也不要执行。
|
||||
|
||||
## 14. Computed Property 必须明确一致性边界
|
||||
## 9. 编译期信息必须消除运行时工作
|
||||
|
||||
`computed_property` 通过 synchronized view 读取依赖项。这个 view 只允许读取和 computed property 本身处于同一个 resolved lock slot 的属性。
|
||||
|
||||
所以依赖 `min_speed`、`max_speed` 的 `speed_span` 应该和它们进入同一个同步组:
|
||||
Typed API 在编译期知道目标 Property:
|
||||
|
||||
```cpp
|
||||
synchronization(
|
||||
sync_all_independent,
|
||||
sync_group("speed", "min_speed", "max_speed", "speed_span")
|
||||
)
|
||||
device.read<&Device::serial_number>();
|
||||
```
|
||||
|
||||
这样一致性关系由同步计划明确表达,而不是让 getter 随意读取任意字段。
|
||||
对于 stored read-only property,编译期路径直接绕过同步。
|
||||
|
||||
### Trusted Accessor
|
||||
同样,对只读属性的 typed write 应该通过 `requires` 从接口中消失,而不是运行后再拒绝。
|
||||
|
||||
`trusted_computed_property` 和 `trusted_accessor_property` 会直接调用对象上的受信任成员函数,设计上绕开 synchronized view 的依赖检查。
|
||||
动态 key API 因为 key 只能运行期确定,所以才做 runtime check。
|
||||
|
||||
### 原则
|
||||
|
||||
**默认优先 synchronized computed property。只有 accessor 自身明确拥有或保证同步语义时才使用 trusted accessor。**
|
||||
静态事实优先变成 `constexpr`、`requires`、`if constexpr`,不要变成 runtime branch。
|
||||
|
||||
## 15. Runtime Access 是边界能力
|
||||
## 10. Synchronization 描述的是可变一致性域
|
||||
|
||||
`Property_Object_Base` 提供 type-erased runtime interface,核心输入包括:
|
||||
Synchronization 的目的,是协调 mutable managed state。
|
||||
|
||||
- string key;
|
||||
- 不传 mode 时使用 intrinsic access;
|
||||
- 只有选择 `external` 或 `persistence` 投影时才使用 `Managed_Access_Mode`;
|
||||
- `std::type_info`;
|
||||
- 显式 result code。
|
||||
默认模式:
|
||||
|
||||
它适用于编译期不知道具体类型的 adapter。
|
||||
```text
|
||||
independent
|
||||
shared
|
||||
unsynchronized
|
||||
```
|
||||
|
||||
它不应该成为把所有正常 typed C++ 代码动态化的理由。
|
||||
Group 让多个可变 Property 共享一个锁域。
|
||||
|
||||
Read-only stored property 即使被宽泛规则包含,也会从最终 resolved topology 中移除。
|
||||
|
||||
### 原则
|
||||
|
||||
**能在编译期确定的代码就留在编译期;只有真正跨动态边界时才进入 runtime path。**
|
||||
Synchronization 解决 mutable consistency,不解决可见性。
|
||||
|
||||
## 16. Compile-time Error 和 Runtime Error 分工明确
|
||||
## 11. Computed Read-Only 是特殊情况
|
||||
|
||||
Structive 对静态可知问题尽量在编译期拒绝:
|
||||
Computed Property 自身可以只读,但它可能依赖可写字段。
|
||||
|
||||
- member 未注册;
|
||||
- key 重复;
|
||||
- 同一成员存储被重复注册;
|
||||
- single-valued category 重复;
|
||||
- 非 inheritable Attribute 被放入 `defaults(...)`;
|
||||
- accessor 实际能力与声明 capability 冲突。
|
||||
Computed value 本身没有可写存储,但读取它时可能需要 mutable dependency 的一致快照。
|
||||
|
||||
Runtime failure 留给 runtime 输入和 runtime 配置:
|
||||
`Synchronized_Computed_Accessor` 因此使用 synchronized read view。需要原子一致性的 writable dependency 应和 computed property 处于同一个同步域。
|
||||
|
||||
- 动态 key 不存在;
|
||||
- 动态属性对该 view 不可访问;
|
||||
- synchronization plan 引用了未知 key;
|
||||
- runtime 同步规则重复配置同一个 property;
|
||||
- runtime type mismatch。
|
||||
Read-only stored dependency 没有 managed writer,所以可以直接读取而无需锁。
|
||||
|
||||
### 原则
|
||||
|
||||
**静态可知的 Schema 错误不要拖到运行时;真正动态的 adapter 输入也不要硬伪装成编译期问题。**
|
||||
不要给 read-only stored field 创建 mutex。Computed read 的同步只服务于需要一致性的 mutable dependency。
|
||||
|
||||
## 17. 同步策略必须保持可替换
|
||||
## 12. 只有一套 Attribute 协议
|
||||
|
||||
`Property_Object<Derived, Lock_Policy>` 支持同步策略,默认是 `Shared_Mutex_Policy`,同时提供 `No_Lock_Policy`。
|
||||
Core 与 Extension 共用同一套 Attribute mechanism。
|
||||
|
||||
这是重要架构缝隙。Core 语义不应该和某一种 mutex 或某一个全局 scheduler 焊死。
|
||||
Attribute 拥有 category,并可以声明 single-valued 与 inheritable 语义。
|
||||
|
||||
`No_Lock_Policy` 只是取消真实互斥,不代表并发访问自动安全。
|
||||
UI、serialization、诊断等新领域不应该另起第二套 metadata system。
|
||||
|
||||
## 18. Extension 设计规则
|
||||
### 原则
|
||||
|
||||
一个好的 Structive Extension 应该:
|
||||
新的 metadata domain 应扩展 Attribute protocol,而不是创造另一套框架。
|
||||
|
||||
1. 定义属于自己领域的 category。
|
||||
2. 复用 Core Attribute 协议。
|
||||
3. 只解释自己拥有或明确依赖的 category。
|
||||
4. 依赖 Core,而不是要求 Core 反向依赖自己。
|
||||
5. 把领域 fallback 行为留在扩展里。
|
||||
6. 优先消费已有 Schema,不复制第二棵 descriptor tree。
|
||||
7. 不因为 adapter 需要便利规则就修改 Core 基础语义。
|
||||
## 13. Category 必须有明确所有者
|
||||
|
||||
## 19. Core 的非目标
|
||||
定义 Attribute category 的组件拥有它的语义。
|
||||
|
||||
Structive Core 不应该同时变成:
|
||||
Presentation 拥有 Presentation Category。Core 可以保存、遍历、泛型读取,但不解释它。
|
||||
|
||||
依赖方向保持:
|
||||
|
||||
```text
|
||||
Extension → Core
|
||||
Core -X→ Extension
|
||||
```
|
||||
|
||||
### 原则
|
||||
|
||||
Core 可以存储未知 Extension metadata,但不能学习 Extension 语义。
|
||||
|
||||
## 14. Defaults 只做 Metadata 继承
|
||||
|
||||
`defaults(...)` 用于 inheritable Attribute,不用于偷偷执行行为。
|
||||
|
||||
Property-level metadata 可以覆盖同一 single-valued category 的 object default。
|
||||
|
||||
Intrinsic capability 不允许继承,因为每个 Property 自己的读写能力必须单独成立。
|
||||
|
||||
### 原则
|
||||
|
||||
Defaults 只降低 metadata 重复,不得变成隐藏行为引擎。
|
||||
|
||||
## 15. Validation 必须显式
|
||||
|
||||
Constraint 描述有效值,但不自动塞进每次 `write()`。
|
||||
|
||||
```cpp
|
||||
auto error = validate_property_value<&Device::temperature>(schema, candidate);
|
||||
```
|
||||
|
||||
单字段 Validation、跨字段 invariant、transaction、rollback 是不同操作。
|
||||
|
||||
### 原则
|
||||
|
||||
不要让 `write()` 变成 validation + event + transaction + rollback 的黑盒工作流。
|
||||
|
||||
## 16. Runtime Access 是适配能力,不是主要编程模型
|
||||
|
||||
`Property_Object_Base` 提供动态 key 的 type-erased access。
|
||||
|
||||
Runtime access 只遵守 intrinsic capability,没有 runtime permission mode。
|
||||
|
||||
Adapter 自己决定是否暴露某个 Property、是否调用 runtime read/write。
|
||||
|
||||
### 原则
|
||||
|
||||
普通 C++ 业务代码优先 member-pointer typed API;runtime access 留给动态边界。
|
||||
|
||||
## 17. Compile-Time Error 与 Runtime Error 分工明确
|
||||
|
||||
静态 typed operation 应在编译期拒绝不可能的结构操作,例如:
|
||||
|
||||
- 写 intrinsic read-only property;
|
||||
- 对 read-only property 请求 typed unique guard;
|
||||
- 读取 write-only property。
|
||||
|
||||
Runtime key API 才使用 `Runtime_Access_Result` 返回动态错误。
|
||||
|
||||
### 原则
|
||||
|
||||
静态可知的 Property 错误不要拖到运行期。
|
||||
|
||||
## 18. Synchronization Policy 必须保持可替换
|
||||
|
||||
`Shared_Mutex_Policy` 提供真实 shared/exclusive lock。`No_Lock_Policy` 不保存真实 mutex。
|
||||
|
||||
NoLock 不应该分配假的 mutex array,也不应该构造无意义的 lock object。
|
||||
|
||||
### 原则
|
||||
|
||||
一个 Policy 移除某项能力时,应尽可能同时移除它的存储和热路径成本。
|
||||
|
||||
## 19. 每实例 Synchronization Override 只让使用者付费
|
||||
|
||||
默认 resolved topology 每个类型共享。对象可以显式传入 `Property_Synchronization` 覆盖。
|
||||
|
||||
只有这种对象才保存 override layout。Copy/Move construction 保留该布局;Assignment 保留目标对象自身的 synchronization policy。
|
||||
|
||||
### 原则
|
||||
|
||||
默认路径不为少数实例才使用的功能承担存储成本。
|
||||
|
||||
## 20. Extension 自己决定领域行为
|
||||
|
||||
Persistence Extension 可以根据自己的 metadata 决定保存字段,GUI 可以决定 editability,RPC 可以实现 authorization。
|
||||
|
||||
这些系统可以读取 Structive 的 `readable`、`writable`、`sensitive` 或自定义 Attribute,但 Structive 不替它们做策略决定。
|
||||
|
||||
### 原则
|
||||
|
||||
Core 描述结构,Consumer 在自己的边界决定行为。
|
||||
|
||||
## 21. Core 的非目标
|
||||
|
||||
Property Core 不准备成为:
|
||||
|
||||
- Authorization Engine;
|
||||
- ORM;
|
||||
- JSON 库;
|
||||
- GUI 框架;
|
||||
- RPC 框架;
|
||||
- signal/slot 系统;
|
||||
- 事务引擎;
|
||||
- 替代所有语言能力的“万能反射”。
|
||||
- JSON Library;
|
||||
- RPC Framework;
|
||||
- GUI Binding Framework;
|
||||
- Transaction Manager;
|
||||
- Event Bus;
|
||||
- Scripting Engine。
|
||||
|
||||
Structive 应该提供足够强的结构契约,让这些系统来消费它。
|
||||
这些系统可以消费 Structive,但应该独立存在。
|
||||
|
||||
## 20. 演进原则
|
||||
## 22. 演进审核规则
|
||||
|
||||
修改库时依次问:
|
||||
以后扩展 Structive 时逐条检查:
|
||||
|
||||
1. 这是 structural model、instance management 还是 extension 的职责?
|
||||
2. 这个新概念本质上是不是一个 Attribute category,而不是新的 metadata channel?
|
||||
3. 这个错误能否在编译期发现?
|
||||
4. 修改后是否仍然保留原生 C++ 成员语义?
|
||||
5. Raw access 与 managed access 的边界是否仍然清晰?
|
||||
6. 是否把 synchronization 和 validation、transaction、event 混在一起了?
|
||||
7. Core 是否开始理解本应属于 Extension 的领域概念?
|
||||
8. Member pointer 是否仍然是 typed API 最自然的身份?
|
||||
9. 新的 convenience API 是否重复制造了另一条同语义路径?
|
||||
10. 是否保持了已有函数签名和功能语义,而不是悄悄改义?
|
||||
1. 它是在增强普通 C++,还是替代普通 C++?
|
||||
2. 这个信息属于类型还是实例?
|
||||
3. 这是 intrinsic structural capability,还是外部 policy?
|
||||
4. 编译期信息能不能直接消掉运行时工作?
|
||||
5. Read-only stored property 是否仍然完全不进入 lock topology?
|
||||
6. Synchronization 是否只服务于 mutable consistency?
|
||||
7. Validation 是否仍然显式?
|
||||
8. Extension 是否拥有自己的 category 语义?
|
||||
9. Runtime adaptation 是否与 typed business API 保持分离?
|
||||
10. 新 Core 概念是否真的普适?
|
||||
|
||||
如果一个功能连续违反这些问题,应先重新考虑它属于哪一层,而不是立刻实现。
|
||||
## 23. 架构总结
|
||||
|
||||
## 21. 架构总结
|
||||
|
||||
Structive 最强的形态应该是少量强概念,而不是大量魔法便利接口:
|
||||
最终架构:
|
||||
|
||||
```text
|
||||
普通 C++ 类型
|
||||
+ 显式 Schema
|
||||
+ 一套 Attribute 模型
|
||||
+ 显式 Capability
|
||||
+ 显式 Validation
|
||||
+ 显式 Synchronization
|
||||
+ 可选 Managed Instance 行为
|
||||
+ Extension 自己解释自己的语义
|
||||
Native C++ struct
|
||||
│
|
||||
├── raw C++ access
|
||||
│
|
||||
└── Structive Schema
|
||||
│
|
||||
├── intrinsic readable/writable
|
||||
├── Attributes
|
||||
├── Constraints
|
||||
├── synchronization description
|
||||
│ └── 只有 mutable consistency domain 创建锁
|
||||
└── managed object
|
||||
├── typed read/write
|
||||
├── guards
|
||||
├── traversal
|
||||
└── intrinsic runtime access
|
||||
|
||||
External systems
|
||||
├── GUI policy
|
||||
├── RPC policy
|
||||
├── persistence policy
|
||||
└── other domain policy
|
||||
|
||||
外部 Policy 消费 Structive 的结构事实,但不是 Structive Core 的 access mode。
|
||||
```
|
||||
|
||||
当泛型系统能够理解业务类型、却不需要接管业务类型时,Structive 的价值最大。
|
||||
一句话概括:
|
||||
|
||||
> **Structive 描述 Property 是什么、它自身能做什么;Structive 不决定谁能使用它。**
|
||||
|
||||
Reference in New Issue
Block a user