组合(Composition)

组合是一种强拥有关系,表示“部分”是“整体”的生命周期的一部分。如果整体被销毁,那么它的所有部分也会被自动销毁。

可以把组合想象成一个房子和它的墙壁。你不能把墙壁从房子里拿出来,让它们独立存在。如果房子被拆除,墙壁也就不复存在了。

主要特点:

  • 强生命周期依赖: 部分对象的生命周期由整体对象控制。

  • 独占拥有: 一个部分只能属于一个整体。

  • 创建关系: 通常,整体对象负责创建其部分对象。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <string>

// 部分类:引擎
class Engine {
private:
std::string type;
public:
Engine(std::string t) : type(t) {
std::cout << "Engine (" << type << ") created." << std::endl;
}
~Engine() {
std::cout << "Engine (" << type << ") destroyed." << std::endl;
}
};

// 整体类:汽车
class Car {
private:
// 组合关系:Car 拥有一个 Engine 对象
// Engine 对象的生命周期由 Car 控制
Engine engine;
public:
// Car 构造函数负责创建 Engine 对象
Car(std::string engine_type) : engine(engine_type) {
std::cout << "Car created." << std::endl;
}
~Car() {
std::cout << "Car destroyed." << std::endl;
// Engine 对象在 Car 析构时自动销毁
}
};

int main() {
Car myCar("V8");
// 当 myCar 对象离开作用域或被销毁时,它所拥有的 Engine 对象也会被销毁。
return 0;
}

输出:

1
2
3
4
Engine (V8) created.
Car created.
Car destroyed.
Engine (V8) destroyed.

聚合(Aggregation)

聚合是一种弱拥有关系,表示“部分”可以独立于“整体”存在。即使整体被销毁,部分仍然可以继续存在。

可以把聚合想象成一个部门和它的员工。员工可以加入或离开一个部门,但他们仍然是独立的个体。即使部门解散了,员工并不会消失。

主要特点:

  • 弱生命周期依赖: 部分对象的生命周期不依赖于整体对象。

  • 共享拥有: 一个部分可以被多个整体共享。

  • 引用关系: 通常通过指针或引用来建立关系。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>
#include <string>
#include <vector>

// 部分类:员工
class Employee {
private:
std::string name;
public:
Employee(std::string n) : name(n) {
std::cout << "Employee (" << name << ") created." << std::endl;
}
std::string getName() const {
return name;
}
~Employee() {
std::cout << "Employee (" << name << ") destroyed." << std::endl;
}
};

// 整体类:部门
class Department {
private:
// 聚合关系:Department 包含指向 Employee 对象的指针
// Department 不拥有 Employee 对象的生命周期
std::vector<Employee*> employees;
std::string name;
public:
Department(std::string n) : name(n) {}

void addEmployee(Employee* emp) {
employees.push_back(emp);
}

~Department() {
std::cout << "Department (" << name << ") destroyed." << std::endl;
// 注意:Department 析构时,不会销毁 Employee 对象
}
};

int main() {
// Employee 对象独立创建,其生命周期不受 Department 控制
Employee* emp1 = new Employee("Alice");
Employee* emp2 = new Employee("Bob");

{
Department sales_dept("Sales");
sales_dept.addEmployee(emp1);
sales_dept.addEmployee(emp2);
} // sales_dept 离开作用域,被销毁,但 emp1 和 emp2 仍然存在

// 此时,部门对象已经销毁,但员工对象仍然存在
std::cout << "Alice's status: Still exists." << std::endl;

// 必须手动释放 Employee 对象
delete emp1;
delete emp2;

return 0;
}

输出:

1
2
3
4
5
6
Employee (Alice) created.
Employee (Bob) created.
Department (Sales) destroyed.
Alice's status: Still exists.
Employee (Alice) destroyed.
Employee (Bob) destroyed.

总结

特性 组合(Composition) 聚合(Aggregation)
关系 “部分”是“整体”的一部分 “部分”一个“整体”的成员
生命周期 强依赖,整体销毁部分也销毁 弱依赖,整体销毁部分可继续存在
拥有关系 独占拥有 共享拥有
实现方式 通常是成员变量 通常是指针或引用成员变量
类比 房子和墙壁 部门和员工
适用场景 当部分没有整体就无意义时 当部分可以独立存在或被共享时

在实际编程中,区分这两种关系对于正确管理内存和设计类之间的耦合至关重要。