在设计复杂软件系统时,理解组件内部如何交互,与了解它们如何外部连接同样关键。这就是“UML组合结构图成为系统架构师和开发人员不可或缺的工具。它提供了分类器内部结构的细致视图,揭示了构成类或组件的各个部分,以及这些部分如何协作以满足系统需求。
本指南探讨了组合结构图的机制、符号表示及其实际应用。我们将超越高层次的概述,深入分析定义这种建模技术的具体关系、角色和语义规则。

🧩 什么是组合结构图?
组合结构图(CSD)是统一建模语言(UML)中的一种结构图。它描述了分类器的内部结构。虽然标准类图展示了类的属性和操作,但并未明确展示该类的内部组成。
组合结构图弥补了这一空白。它使您能够可视化:
- 部件: 构成分类器的内部组件。
- 端口: 部件与外部世界或其他部件连接的交互点。
- 连接器: 定义端口之间数据或控制流的链接。
- 接口: 结构所提供的或所需的服务。
可以将其想象为对一段软件或硬件进行“CT扫描”。你看到的是器官(部件)、端口(连接)以及使它运行的神经系统(连接器)。
🛠️ 核心元素与符号表示
要构建准确的组合结构图,必须理解特定符号及其含义。符号表示的精确性可避免在开发生命周期中产生歧义。
1. 分类器框架
主矩形代表组合结构本身。它通常对应于其他UML图中的类、组件或节点。在此框架内,您定义内部架构。
2. 部件(内部实例)
部件表示由组合结构所拥有的类的实例。它与类本身是不同的。
- 符号表示: 一个带有部件名称的小矩形,通常带下划线,后跟冒号和类名。
- 示例:
browser : WebBrowser - 可见性: 部件可以是私有的、受保护的或公共的,由
-,#,或+.
3. 端口(交互点)
端口是零件或复合结构边界上的一个命名交互点。它定义了结构与外部环境或其他内部零件交互的位置。
- 符号表示: 一个附着在零件或复合结构边界上的小方框。
- 作用: 它指定了零件用于通信的接口。
4. 接口(契约)
接口定义了交互的契约。它们指明了端口需要或提供的内容。
- 所需接口: 零件需要服务的“孔”。符号表示:带一条线的圆圈。
- 提供接口: 零件提供服务的“球”。符号表示:实心圆圈。
5. 连接器(链接)
连接器将端口连接在一起。它们定义了零件之间的数据或控制流。
- 符号表示: 连接两个端口的一条实线。
- 关联: 直接连接两个端口。
- 依赖: 表示一个零件依赖于另一个零件的功能。
📊 对比:复合结构图与类图
人们常常混淆复合结构图与类图。虽然两者都涉及结构,但它们的关注点有很大不同。
| 特性 | 类图 | 复合结构图 |
|---|---|---|
| 范围 | 系统级或包级 | 单一分类器内部 |
| 重点 | 属性和操作 | 内部部件和连接 |
| 粒度 | 高层逻辑 | 低层架构 |
| 用途 | 数据库模式,API设计 | 微服务,硬件集成 |
当需要理解整个应用程序中的数据模型和逻辑时,请使用类图。当需要理解特定组件如何由更小的子组件构建时,请使用组合结构图。
🚀 创建组合结构图的逐步指南
创建一个稳健的图表需要有条不紊的方法。遵循以下步骤,以确保您的模型准确且对利益相关者有用。
步骤1:识别分类器
首先,定义您希望分解的主要类或组件。这就是“复合体”。例如,考虑一个PaymentGateway类。
- 绘制一个标有
PaymentGateway. - 确保这是您内部结构的顶层容器。
步骤2:定义内部部件
将主要分类器分解为其组成部分。哪些子组件是此分类器运行所必需的?
- 识别依赖关系。它是否需要一个安全的连接管理器?
- 识别数据处理器。它是否需要一个事务日志记录器?
- 将这些作为小矩形添加到主框架内。
- 示例:添加
securityManager : SecurityModule和日志记录器:事务日志.
步骤3:建立端口
部件需要通信方式。在每个发生交互的部件边界上定义端口。
- 对于
支付网关,你可能需要一个外部端口,用于接收前端的请求。 - 对于
安全管理器,你可能需要一个端口来请求加密服务。 - 在部件的边界上绘制小方框。
- 清晰地标记它们,例如
认证端口或数据端口.
步骤4:定义接口
说明每个端口所需或提供的服务。这确保各部件确切知道预期内容。
- 在端口上附加接口符号。
- 使用“棒棒糖”符号表示提供的接口。
- 使用“插座”符号表示所需的接口。
- 示例:
安全管理器可能需要一个名为加密服务.
步骤5:连接部件
在端口之间绘制线条(连接器)以定义信息流。
- 连接
支付网关端口到安全管理员端口。 - 确保数据流的方向在逻辑上是合理的。
- 如果涉及多个角色,请标记连接器(例如,
角色1,角色2).
步骤6:审查与验证
在最终确定前,请检查图表的逻辑一致性。
- 所有必需的接口都已连接吗?
- 是否存在任何不通信的孤立部分?
- 内部结构是否支持主类的外部行为?
🧪 现实场景:微服务架构
复合结构图在现代微服务架构中尤其有效。让我们来分析一个订单处理服务.
场景分解
该服务接收订单,进行验证,计算运费,并确认付款。在内部,该服务由多个逻辑模块组成。
- 订单验证器: 检查数据完整性。
- 运费计算器: 根据重量计算费用。
- 支付处理器: 处理交易逻辑。
- 日志记录器: 记录审计轨迹。
结构模型
在图中,订单处理服务是复合框架。上面的四个模块是各个部分。订单验证器需要一个接口验证规则。运费计算器需要位置数据。支付处理器需要支付网关API连接器将主服务端口与这些内部需求连接起来。
为什么在这里使用此图?
- 清晰性:它表明
订单处理服务不是单一整体,而是由不同关注点组成的复合体。 - 解耦:它强调
支付处理器只要提供所需接口,就可以互换。 - 部署:它暗示了这些部分可能在物理上部署的位置(例如,不同的容器中)。
🔗 关系与基数
理解各部分之间的关系至关重要。基数定义了复合体中一个部分可以存在多少个实例。
1:1 关系
每个复合体实例对应一个部分实例。
- 示例: 一个
汽车恰好有一个发动机. - 符号表示: 在零件端有一条带单个横杠的线。
1:N 关系
一个组合体可以包含多个零件的实例。
- 示例: 一个
购物车包含多个购物项。 - 符号表示: 在零件端有一个乌鸦爪符号。
0:N 关系
组合体可以在没有零件的情况下存在,或者包含多个零件。
- 示例: 一个
文档可能有零个或多个页面. - 符号表示: 带有可选横杠的乌鸦爪符号。
错误的基数可能导致运行时错误或架构瓶颈。务必验证零件的生命周期。当组合体消亡时,零件是否也随之消亡?还是它可以比组合体存在得更久?
🎯 有效建模的最佳实践
为保持高质量的图表,请遵循以下指南。
- 保持简洁:不要在图表中塞入过多的组件。如果一个复合体包含超过10个部分,应考虑进一步拆分。
- 命名一致:为部件和端口使用清晰、描述性的名称。避免使用像这样的通用术语:
部件1. - 分组:使用嵌套的框架来分组相关部件。这可以减少视觉混乱。
- 关注点分离:不要将行为图(如序列图)混入结构中。保持结构与行为分离。
- 版本控制:将这些图表视为代码。与源代码一起进行版本控制,以确保文档与实现一致。
⚠️ 需要避免的常见陷阱
即使经验丰富的架构师在建模内部结构时也可能出错。请注意这些常见问题。
1. 过度设计
不要为每个类都创建复合结构。仅当内部组合足够复杂、值得可视化时才进行建模。简单的数据模型不需要如此详细的层次。
2. 忽视生命周期
部件的生命周期通常与复合体不同。确保你的模型反映出部件是随复合体一起创建和销毁,还是独立持续存在。
3. 模糊的接口
确保接口定义清晰。如果端口需要接口,请明确指出所需的方法。模糊的接口会导致集成错误。
4. 循环依赖
避免创建循环依赖,即部件A需要部件B,而部件B又需要部件A。这会在设计逻辑中造成死锁。通过引入一个中间接口或抽象类来打破循环。
🔍 高级概念:嵌套复合体
复合结构图最强大的特性之一就是能够嵌套。你可以将复合体中的一个部件视为一个复合体本身。
想象一个服务器类。在服务器框架内,有一个数据库 部分。该 数据库 部分本身可以是一个包含 表 部分和 索引 部分。这种嵌套结构支持分层建模。
- 优势: 它使你能够在不丢失上下文的情况下深入复杂性。
- 优势: 它支持分层展示。你可以在一页上展示高层架构,在另一页上展示底层细节。
- 注意: 嵌套过多会使图表难以阅读。将嵌套深度限制在两到三层。
🤝 与开发团队协作
该图表在设计与实现之间起到了桥梁作用。
- 对于开发人员: 它明确了对象实例化的具体方式。它告诉他们需要注入哪些依赖项。
- 对于测试人员: 它有助于创建覆盖内部交互的测试用例,而不仅仅是外部输入。
- 对于运维人员: 它有助于制定部署策略,展示哪些部分可以独立容器化。
在冲刺规划期间,定期与团队一起审查这些图表。这可以确保所有参与构建过程的人都理解架构意图。
📝 关键要点总结
UML组合结构图是一种专门用于深入架构洞察的工具。它超越了类的表面层次,揭示了内部的运作机制。通过关注部件、端口和连接器,架构师可以设计出模块化、可维护且稳健的系统。
需要记住的关键点:
- 它用于建模分类器的内部结构。
- 部件是实例;端口是交互点。
- 接口定义了通信的契约。
- 连接器将部件连接起来以实现功能。
- 使用嵌套组合来处理层次化复杂性。
通过应用这些原则,您能够确保系统设计不仅仅是类的集合,而是一个协调良好的交互组件集合。这种精确性减少了技术债务,并在系统扩展时促进了更顺畅的集成。
请记得保持您的图表更新。随着代码的演进,结构也必须随之演变。静态的图表是一种负担;而动态的模型则是一种资产。












