4. 包图与模型组织

当模型从几十个元素增长到几百甚至上千个元素时,真正决定项目能否持续维护的,往往不是单个类或状态机画得多精细,而是模型有没有被组织成清晰、可导航、可复用的结构。包(Package)就是 Cameo Systems Modeler 中承担这一职责的核心容器:它既是命名空间,又是依赖与导入关系的载体,也是团队分工和模型库复用的基本单位。

包的本质:命名空间 + 容器 + 依赖端点

在 SysML/UML 语义中,包首先是一个 Namespace(命名空间)。包内元素的全限定名由外层包名逐级拼接而成,例如 Vehicle::Powertrain::Engine 表示 Engine 位于 Powertrain 包内,而 Powertrain 又位于 Vehicle 包内。这意味着两个不同包中可以存在同名元素,只要它们的全限定名不同就不会冲突。包同时是容器,通过 containment(包含)关系持有其内部元素;包还是依赖关系的端点,Import、Merge、Access 等关系都发生在包与包之间。

理解这一点非常关键:包图不是“画几个文件夹”,而是在表达命名空间层级、可见性规则和依赖方向。一个组织良好的包结构,能让模型使用者在不了解全部细节的情况下,仅凭包名和依赖箭头就判断出“谁能看到谁、改动会影响谁”。

包图的绘制要点

在 Cameo 中新建包图(Package Diagram)后,从 Containment 树拖入包元素即可。包的标准符号是左上角带小标签页的矩形,包名写在矩形内部;包之间的依赖用虚线箭头表示,箭头从依赖方指向被依赖方。常见的几种关系需要区分清楚:

  • Containment(包含):用带十字圆圈的实线或嵌套画法表示,表示“物理上放在里面”,是结构层级。
  • «import»:公有导入,被导入包的公有元素在本包中可直接以简单名引用,且会传递到本包的子包。
  • «access»:私有导入,被导入元素只在本包内可见,不向子包传递。
  • «merge»:包合并,把目标包的内容合并进源包,常用于把通用库合并进项目专用包。

绘制时建议遵循“一屏一主题”原则:一张包图只表达一个层级的组织关系,不要把所有子包和所有依赖都塞进同一张图。对于大型模型,可以按视图分层——顶层画系统级包划分,第二层画各领域包内部结构,第三层才画具体元素。

包图:命名空间层级与导入/合并关系 Vehicle Powertrain Engine Transmission «block» EngineController 全限定名:Vehicle::Powertrain::Engine Chassis BrakeSystem Suspension «block» Wheel CommonLibrary «block» PhysicalQuantity «valueType» Real «enumeration» Unit 可被多个项目复用的基础类型库 ProjectSpecific «block» CustomEngine «block» CustomBrake 合并通用库后扩展项目专用元素 «import» «access» «merge» «import» 公有导入 «access» 私有导入 «merge» 包合并

包导入与合并:可见性规则决定引用方式

导入和合并是包图最容易混淆的部分,需要从“可见性”和“内容复制”两个角度区分。

«import» 与 «access» 属于引用式导入。它们不复制元素,只是在源包中建立一条指向目标包的可见性通道。使用 «import» 时,目标包的公有元素在源包及其所有子包中都可以用简单名引用;使用 «access» 时,只有源包自身能引用,子包必须重新导入。例如,若 Vehicle::Powertrain 用 «import» 导入了 CommonLibrary,那么 Vehicle::Powertrain::Engine 可以直接写 PhysicalQuantity;若改用 «access»,则 Engine 必须写全限定名或由 Powertrain 再次显式导入。

«merge» 属于内容合并式关系。包合并会把目标包(被合并包)中的元素“并入”源包,源包中同名元素会与目标包元素合并,不同名元素则被添加进来。它常用于把通用库合并进项目专用包,使项目包获得库中全部定义,同时允许在项目包中覆盖或扩展特定元素。需要注意的是,合并是双向语义的:源包中被合并进来的元素与目标包保持同一性,修改目标包会影响所有合并它的包,因此合并关系应谨慎使用,避免形成难以追踪的隐式耦合。

实践建议:优先使用 «import» 建立显式依赖,仅在确实需要“继承整套库定义并允许本地覆盖”时使用 «merge»。合并链越长,模型的可追溯性越差。

模型命名空间管理

命名空间管理的核心目标是:让全限定名稳定、可预测,避免重名冲突和循环依赖。在 Cameo 中可以通过以下方式落实:

  • 统一命名规范:包名使用大驼峰(如 Powertrain),元素名使用业务语义(如 EngineController),避免使用 Package1、Block_2 这类自动生成名。
  • 控制层级深度:一般建议 3~5 层,过深会导致全限定名冗长、引用困难;过浅则无法隔离不同领域。
  • 避免循环导入:若 A 导入 B、B 又导入 A,会造成命名空间解析歧义。可用依赖矩阵或 Cameo 的 Dependency Matrix 检查。
  • 使用 Root 包隔离项目:每个项目建立独立 Root 包,通用库放在共享 Root 下,通过导入引用,避免直接修改库内容。

当出现同名元素时,Cameo 会在引用处提示歧义,此时应使用全限定名或调整导入范围来消除冲突,而不是简单重命名破坏已有引用。

模型库与复用策略

模型库的价值在于把经过验证的类型、接口、单位、枚举等沉淀为可复用资产。一个可落地的复用策略通常包含三层:

层级内容复用方式
基础库单位、值类型、基础枚举、通用接口«import» 到各项目包
领域库某领域通用块、端口类型、约束«import» 或 «merge» 到领域包
项目包项目专用块、参数、具体实例引用基础库与领域库,本地扩展

复用时的关键判断是:被复用元素是否稳定。若基础库中的 PhysicalQuantity 被 20 个项目引用,一旦修改其属性,所有项目都会受影响。因此基础库应经过评审并版本化,项目包通过导入引用而非复制粘贴来使用它。对于需要本地定制的场景,可在项目包中创建继承自库元素的子类型,而不是直接修改库元素。

常见误区:把通用库元素直接复制到项目包中“图方便”。这会导致同一概念出现多份定义,后续库升级时无法同步,模型一致性迅速恶化。

综合来看,包图与模型组织不是建模完成后的“整理工作”,而是贯穿建模始终的结构决策。先规划命名空间层级,再明确导入与合并关系,最后把稳定内容沉淀为库,模型才能从一次性交付物变成可持续演进的资产。