Files
bim_engine/.sisyphus/drafts/framework-audit-report.md
yuding 4a09d52283 feat(clipping): implement hide/recover toggle for all section dialogs
Update all three section dialogs to support hide/show toggle:

SectionAxisDialogManager:
- onHideToggle now calls hideSection()/recoverSection()

SectionBoxDialogManager:
- onHideToggle now calls hideSection()/recoverSection()

SectionPlanePanel:
- Add isHidden state tracking
- Change onHide to onHideToggle(isHidden)
- Add setHiddenState/getHiddenState methods
- Update button to toggle active state

SectionPlaneDialogManager:
- Switch to onHideToggle callback
- Call hideSection()/recoverSection() based on toggle state

Behavior: Click hide button to hide section, click again to recover.
2026-02-02 16:36:17 +08:00

231 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# iflow-engine 框架架构审核(代码 + 文档)
日期2026-01-29
## 范围
本审核仅评估 `iflow-engine` SDK 的**内部框架/架构设计**,依据:
- `src/` 下的源代码
- `docs/` 下的架构与模块文档
不在本次范围内:
- 功能完整性
- UI/交互体验优劣
- 重构路线/落地方案/实现细节(按你的要求不输出)
已确认的前提(来自你的要求):
- 保留 `ManagerRegistry` 作为核心设计(单例 + 服务定位器)。
- SDK 需要支持同一页面多个 viewer 实例。
- 主题/语言是全局共享。
- 事件应当按 `BimEngine` 实例隔离。
- Components 设计上应当严格纯 UI不触达 registry、不发布全局事件。
- Components 也不应直接订阅/读取全局主题/国际化服务theme/locale 应由 manager 注入或推送更新)。
## 严重级别说明
- **Critical致命**:架构层面存在矛盾或极易引发跨实例破坏。
- **High**:高概率造成长期维护痛点/难追踪 bug。
- **Medium**:明显增加认知负担或存在非小风险的不一致。
- **Low**:质量/风格问题,非结构性,但建议修整。
## 发现的问题清单
### 1) Critical多实例事件隔离诉求与全局单例事件总线结构矛盾
框架把所有事件集中在 `ManagerRegistry` 内部的一个全局 `EventEmitter` 上。
这从结构上决定了:多个 `BimEngine` 实例之间无法做到事件天然隔离。
证据:
- `src/core/manager-registry.ts:31-38``private eventEmitter: EventEmitter = new EventEmitter()`
- `src/core/manager-registry.ts:95-127``emit/on/off` 都委托给这一个 emitter
- `src/core/base-manager.ts:19-34`(所有 Manager 的订阅都通过单例 registry 完成)
影响:
- 多个 viewer 共存时,任一实例发出的事件都可能被所有订阅者收到。
- 事件域是全局的,不是 per-engine 的;如果要隔离,必须在别处“人为做隔离”,但当前框架没有内建边界。
### 2) Critical销毁任一实例会重置全局 registry破坏其他实例
`BimEngine.destroy()` 会调用 `ManagerRegistry.reset()`:清空事件监听并把单例置空。
当页面存在多个引擎实例时,销毁其中一个就可能让其他实例失效。
证据:
- `src/bim-engine.ts:150-164`(调用 `ManagerRegistry.reset()`
- `src/core/manager-registry.ts:82-88``reset()``clear()` emitter 并 `instance = null`
影响:
- 跨实例“断电式”故障;而且故障源头非局部,排查成本高。
### 3) High全局 registry 存放实例态container/wrapper/各类 manager 实例)
`ManagerRegistry` 不只是 locator它持有 `container/wrapper` DOM 节点和大量 manager 实例。
这使它变成一个全局可变的“状态袋”。
证据:
- `src/core/manager-registry.ts:35-70``container`/`wrapper` 与各 manager 字段)
- `src/bim-engine.ts:101-136`(把容器与所有 manager 写入单例)
影响:
- 多实例情况下,“最后初始化的实例”会覆盖 `registry.container/wrapper` 与 manager 引用。
- 排查问题时必须追踪“最后是谁写入了全局状态”。
### 4) High服务定位器边界未被约束叶子层大量直接 getInstance
框架想表达分层,但叶子层代码频繁直接调用 `ManagerRegistry.getInstance()`
这会扩大隐式依赖并增加跳转/追踪成本。
证据(示例,不完全):
- `src/components/button-group/toolbar/buttons/home/index.ts:15-16`
- `src/components/button-group/toolbar/buttons/measure/index.ts:14-18`
- `src/components/button-group/toolbar/buttons/map/index.ts:8-28`
- `src/components/button-group/index.ts:65-68`(组件通过单例 registry 发事件)
- `src/components/engine/index.ts:131-144`Engine 组件通过单例 registry 发事件)
- `src/managers/engine-manager.ts:64-68`(即便继承 `BaseManager`,回调里仍 `getInstance()`
影响:
- 依赖关系在 API/构造函数层面不可见,只能靠全局搜索发现。
- 实际改动往往需要跨层与跨全局状态跳转。
### 5) High组件层通过 registry 直接参与框架通信,削弱了文档里的分层承诺
文档里写明“组件不直接依赖 Manager由 Manager 创建和管理组件实例”。
但代码中组件通过全局 registry 发布事件。
证据:
- 文档承诺:`docs/MODULES/组件模块.md:595-602`
- 反例:`src/components/engine/index.ts:131-144``ManagerRegistry.getInstance().emit(...)`
- 反例:`src/components/button-group/index.ts:65-68`(组件通过 registry 发事件)
影响:
- 组件层通过全局 locator 变得“半业务化/半框架化”。
- 耦合上升,测试与复用更困难。
### 6) HighRightKeyManager 出现重复创建/归属不清
右键管理器至少在两处被创建。
这会导致职责重复,并引入“到底谁是权威实例”的歧义。
证据:
- `src/bim-engine.ts:108``this.rightKey = new RightKeyManager(this.wrapper)`
- `src/managers/engine-manager.ts:50-51``this.rightKey = new RightKeyManager(this.container)`
影响:
- 更高概率出现重复监听、hide/show 不一致、销毁责任不清。
### 7) HighEngine 组件依赖仓库相对路径的底层引擎产物(工程耦合)
代码没有从外部依赖(`iflow-engine-base`)导入,而是通过深层相对路径引入本仓库的 dist 文件。
这会把构建/运行绑定到特定仓库布局。
证据:
- `src/components/engine/index.ts:8-11`(从 `../../../../bim_engine_base/dist/...` 导入 `createEngine`
影响:
- CI/发布构建对目录结构高度敏感。
- 线上发布包与本地开发行为可能不一致。
### 8) MediumBimEngine 订阅主题变化但未保存取消订阅句柄
`BimEngine.init()``themeManager` 订阅后没有保存返回的 `unsubscribe`
证据:
- `src/bim-engine.ts:139-142``themeManager.subscribe(...)` 返回值未保存)
影响:
- 在 SPA 场景反复创建/销毁引擎时可能累积订阅,形成隐性泄漏。
### 9) Medium对话框定位依赖全局 registry.container非实例局部上下文
`BaseDialogManager` 的默认位置计算基于 `this.registry.container`
多实例时这隐含了“全局只有一个有效 container”。
证据:
- `src/core/base-dialog-manager.ts:60-73`(读取 `this.registry.container` 计算位置)
影响:
- 多实例下对话框可能相对“最后写入 registry 的容器”定位,表现不一致。
### 10) Medium分层调用链本身会导致“改动面扩大”层级跳转多
文档明确了 5 层调用链Button → DialogManager → EngineManager → Engine 组件 → 底层引擎)。
哪怕每层都写得干净,累计的间接层也会扩大改动时的触达面。
证据:
- `docs/API调用链.md:714-748`(层级说明)
- `docs/引擎API对接.md:18-66`(架构概览与层级表)
影响:
- 一个功能的内部改动往往需要同步修改 3-5 个位置。
- 这会被外部感知为“框架复杂”,即使逻辑上自洽。
### 11) Medium构建配置禁用代码分割可能削弱 ESM tree-shaking 效果)
库构建使用 `inlineDynamicImports: true`,强制输出单文件 bundle。
证据:
- `vite.config.ts:26-38`
影响:
- 使用方更难获得按需使用/裁剪的收益。
- 打包策略会进一步强化“框架很重”的印象。
### 12) LowEngine.setTheme 为空实现(抽象与实现不一致)
Engine 组件暴露了 `setTheme`,但实现为空。
证据:
- `src/components/engine/index.ts:153-160`
影响:
- 虽然不是典型“架构问题”,但会加重抽象与行为不一致,长期会影响信任度与维护效率。
## 文档一致性备注
整体上文档很完整、意图也清晰(门面 + registry + 分层)。主要不一致/落差集中在:
- 一些分层边界(如“组件不依赖 Manager”在代码里被全局 registry 使用削弱。
- “多实例 + 事件隔离”的需求与当前“全局单例事件域”存在硬冲突。
## 维护成本视角的客观评价(你选的侧重点)
这里把“维护成本”拆成三类:可读性(读懂/定位)、可改动性(改一个点波及范围)、可测试性(写测试/隔离依赖的难度)。
### A. 可读性(读懂/定位)
结论:**中等偏高的认知负担**。架构意图清晰,但“全局可取用 registry”让依赖与调用链变得隐式。
主要原因(按影响排序):
- **隐式依赖**:叶子层普遍 `ManagerRegistry.getInstance()`,使得“一个文件真正依赖哪些子系统”无法从构造函数/参数判断,只能靠全局搜索。
- 证据:`src/components/button-group/toolbar/buttons/home/index.ts:15-16``src/components/button-group/toolbar/buttons/measure/index.ts:14-18``src/components/button-group/toolbar/buttons/map/index.ts:8-28`
- **状态来源不集中**registry 同时存放 DOM 容器(`container/wrapper`)与大量 manager 实例,读代码时需要先搞清楚“谁在什么时候写入了 registry”。
- 证据:`src/core/manager-registry.ts:35-70``src/bim-engine.ts:95-136`
- **层级跳转多且链路分散**你在文档里明确分层L1-L5这使新同学能理解“应该去哪里找”但也意味着定位一个行为经常要横跨 3-5 个文件。
- 证据:`docs/引擎API对接.md:18-66``docs/API调用链.md:714-748`
### B. 可改动性(改一个点波及范围)
结论:**改动面容易扩大**,尤其是新增/调整一个功能时,按规范往往需要在多个层同时补齐。
主要原因:
- **强制的多层落点**:文档对“新增功能对接步骤”规定了 Button→Toolbar→DialogManager→Registry→BimEngine init→EngineManager→Engine 组件的连锁改动;这对一致性有好处,但会让小需求也要跨层改多个位置。
- 证据:`docs/引擎API对接.md:326-517`Step 1-7
- **全局注册表字段扩散**:新增一个 manager 往往意味着在 registry 增字段、在 BimEngine 填充引用随着功能增长registry 越来越像“全局大对象”,改动与回归风险随之增加。
- 证据:`docs/引擎API对接.md:416-446``src/core/manager-registry.ts:35-70``src/bim-engine.ts:120-136`
- **重复实例/归属不清会放大改动成本**:同一能力被多处创建/持有,会导致改动时需要同时修改多个入口,且更容易漏。
- 证据:`src/bim-engine.ts:108``src/managers/engine-manager.ts:50-51`
### C. 可测试性(隔离依赖/写单测的难度)
结论:**偏难**(不是因为 TypeScript/DOM而是因为全局单例与隐式依赖
主要原因:
- **全局单例 + 全局事件域**:测试用例之间需要非常谨慎地清理/隔离 registry 状态与事件订阅,否则容易互相污染。
- 证据:`src/core/manager-registry.ts:31-38``src/core/manager-registry.ts:82-88`
- **组件/manager 直接触达全局状态**:例如 Engine 组件在底层事件回调里直接拿单例 registry 发事件,使得组件测试必须考虑全局副作用。
- 证据:`src/components/engine/index.ts:131-144`
- **订阅/事件监听的释放不完全**:存在订阅未保存/未释放的迹象,会导致测试环境(或 SPA出现隐性泄漏与用例间干扰。
- 证据:`src/bim-engine.ts:139-142``src/components/button-group/index.ts:97-112``src/components/button-group/index.ts:804-817`
### 维护成本总结(一句话)
你的架构“按分层组织代码、让功能落点清晰”的方向是对的;维护成本主要来自 **registry 单例让依赖与状态隐式化**,再叠加 **多层落点规范****少量重复实例/资源释放不全**,使得定位、改动、测试都会更依赖经验与全局搜索。