什么是聚合和组合

聚合(Aggregation)和组合(Composition)是面向对象编程(OOP)、UML 建模中描述整体 - 部分 关系的两种核心关联类型,二者都表示 "整体包含部分",但核心区别在于部分的生命周期是否依赖整体------ 这是理解二者的关键。

一、先明确核心差异(一句话总结)

维度 聚合(Aggregation) 组合(Composition)
核心关系 "拥有" 关系(has-a):整体拥有部分,但部分可独立存在 "包含" 关系(contains-a):整体由部分构成,部分无法脱离整体存在
生命周期依赖 部分的生命周期独立于整体(整体销毁,部分仍可存活) 部分的生命周期完全依赖整体(整体销毁,部分必销毁)
UML 图示 空心菱形 + 实线(菱形在整体端) 实心菱形 + 实线(菱形在整体端)
代码体现 部分对象通常由外部传入,整体不负责创建 / 销毁 部分对象由整体创建(如在构造函数中 new),整体销毁时主动销毁部分
示例 公司 - 员工、汽车 - 轮胎(可拆下来装另一辆车) 人体 - 心脏、订单 - 订单明细(明细不能脱离订单存在)

二、详细拆解

1. 聚合(Aggregation):松散的整体 - 部分关系

聚合是弱关联的整体 - 部分关系,重点是 "整体拥有部分,但部分可独立存在"。

  • 核心特征

    • 部分可以属于多个整体(或不属于任何整体);
    • 整体的创建 / 销毁不会影响部分的生命周期;
    • 代码中通常通过 "依赖注入"(如构造函数传参、setter 方法)将部分对象传入整体,整体仅持有引用,不负责部分的创建和销毁。
  • 示例 1:公司(Company)和员工(Employee)

    • 公司是 "整体",员工是 "部分";

    • 员工可以加入 A 公司,也可以离职加入 B 公司,甚至暂时无公司(独立存在);

    • 即使 A 公司解散(整体销毁),员工依然存在(部分存活)。

    • 代码示例(Java): java

      运行

      复制代码
      // 部分类:员工(可独立存在)
      class Employee {
          private String name;
          public Employee(String name) { this.name = name; }
      }
      
      // 整体类:公司(拥有员工,但不创建/销毁员工)
      class Company {
          private List<Employee> employees;
      
          // 员工由外部传入,公司仅持有引用
          public void addEmployee(Employee emp) {
              employees.add(emp);
          }
      
          // 公司解散时,不会主动销毁员工
          public void dissolve() {
              employees.clear(); // 仅解除引用,员工对象仍存在
          }
      }
      
      // 使用:员工可独立创建,再加入公司
      public class Test {
          public static void main(String[] args) {
              Employee emp1 = new Employee("张三"); // 员工独立存在
              Company company = new Company();
              company.addEmployee(emp1); // 公司"拥有"员工
              company.dissolve(); // 公司解散,emp1仍存在
          }
      }
  • 示例 2:汽车(Car)和轮胎(Tire)

    • 轮胎可以先生产出来存放,再装配到某辆汽车上;
    • 汽车报废后,轮胎可拆下来装到另一辆车上,轮胎本身不会随汽车销毁。
2. 组合(Composition):强耦合的整体 - 部分关系

组合是强关联的整体 - 部分关系,重点是 "部分是整体的不可分割的组成部分,无法独立存在"。

  • 核心特征

    • 部分只能属于一个整体,不能共享;
    • 整体创建时,部分必须同时创建(通常在整体的构造函数中初始化);
    • 整体销毁时,部分必须被销毁(如 Java 中整体对象被 GC 回收,部分对象也会被回收;或手动释放资源);
    • 部分不能脱离整体被单独使用。
  • 示例 1:订单(Order)和订单明细(OrderItem)

    • 订单是 "整体",订单明细是 "部分";

    • 订单明细无法脱离订单存在(没有订单的 "明细" 无业务意义);

    • 创建订单时,明细必须随订单一起创建;删除订单时,明细必须一起删除。

    • 代码示例(Java): java

      运行

      复制代码
      // 部分类:订单明细(无法独立存在)
      class OrderItem {
          private Long productId;
          private Integer quantity;
          public OrderItem(Long productId, Integer quantity) {
              this.productId = productId;
              this.quantity = quantity;
          }
      }
      
      // 整体类:订单(创建/销毁明细)
      class Order {
          private Long orderId;
          private List<OrderItem> items;
      
          // 订单创建时,初始化明细(部分由整体创建)
          public Order(Long orderId) {
              this.orderId = orderId;
              this.items = new ArrayList<>();
          }
      
          // 新增明细:由订单内部创建,不接受外部传入的明细(强控制)
          public void addItem(Long productId, Integer quantity) {
              items.add(new OrderItem(productId, quantity));
          }
      
          // 订单销毁时,明细也被销毁(Java中GC自动回收,若为资源需手动释放)
          public void cancel() {
              items.clear(); // 明细随订单销毁
          }
      }
      
      // 使用:明细无法独立创建和使用
      public class Test {
          public static void main(String[] args) {
              Order order = new Order(1L);
              order.addItem(1001L, 2); // 明细由订单创建
              order.cancel(); // 订单取消,明细也被销毁
              // 无法直接创建OrderItem并使用(无业务意义)
          }
      }
  • 示例 2:人体(Person)和心脏(Heart)

    • 心脏是人体的组成部分,不能脱离人体独立存在;
    • 人体死亡(整体销毁),心脏也会停止工作(部分销毁);
    • 心脏无法属于多个人体。

三、易混淆场景的判断方法

遇到整体 - 部分关系时,用以下两个问题快速区分:

  1. 部分能否脱离整体独立存在?
    • 能 → 聚合(如:书 - 作者,作者可写多本书,也可不写书);
    • 不能 → 组合(如:手机 - 电池,手机专用电池无法脱离手机单独使用)。
  2. 整体销毁时,部分是否必须销毁?
    • 否 → 聚合(如:学校 - 学生,学校解散,学生仍存在);
    • 是 → 组合(如:购物车 - 购物车项,购物车删除,项必删除)。

四、和数据库主从表的关联(补充)

你之前问的主从表,和聚合 / 组合的对应关系:

  • 组合关系 → 主从表强关联(从表外键不允许 NULL,删除主表级联删除从表);
  • 聚合关系 → 主从表弱关联(从表外键允许 NULL,删除主表不影响从表)。

比如:

  • 订单(主表)- 订单明细(从表)是组合关系 → 明细外键不允许 NULL,删订单必删明细;
  • 部门(主表)- 员工(从表)是聚合关系 → 员工外键(部门 ID)允许 NULL(员工可待岗),删部门不删员工(仅置空部门 ID)。

总结

聚合和组合都是 "整体 - 部分" 关系,核心区别是生命周期依赖强度

  • 聚合是 "松散拥有",部分独立;
  • 组合是 "紧密构成",部分依赖整体存活。在设计时,组合用于 "不可分割" 的场景,聚合用于 "可独立存在" 的场景,这也是 UML 建模和代码设计中保证逻辑合理性的关键。
相关推荐
springfancy201321 小时前
高校后勤数字化转型实战:重庆诺怀智慧物业管理系统架构解析
系统架构·学校后勤管理系统·高校后勤管理系统·智慧后勤系统
CinzWS21 小时前
基于Cortex-M3 SoC的eFuse模块--系统架构
系统架构·efuse
测试游记21 小时前
智能MCP系统架构与实现
系统架构
黑尾土拨鼠21 小时前
2025年下半年软考系统架构设计师顺利通过了
系统架构
忍冬行者1 天前
基于虚拟化环境下测试虚拟机的磁盘IO
系统架构
郭涤生1 天前
QT 架构笔记
java·数据库·系统架构
zhou_gai1 天前
供应链计划系统架构实战(五):数据模型设计-全球网络模型与数据分布
大数据·系统架构·制造
虚幻如影1 天前
虚拟机安装统信UOS
系统架构
milanyangbo3 天前
像Git一样管理数据:深入解析数据库并发控制MVCC的实现
服务器·数据库·git·后端·mysql·架构·系统架构