聚合与组合
本课属于 Coddy Java 学习旅程的“面向对象编程”单元。第 48 课,共 87 课。
聚合和组合都是“拥有”关系,但它们在一个关键方面有所不同:所有权和生命周期依赖关系。
在组合关系中,被包含的对象不能脱离容器独立存在。容器销毁时,其中的组成部分也会随之销毁。想想House和它的Room对象:没有房子,房间就无法存在:
class House {
private Room[] rooms;
public House(int numRooms) {
rooms = new Room[numRooms];
for (int i = 0; i < numRooms; i++) {
rooms[i] = new Room(); // House 创建并拥有这些房间
}
}
}在聚合中,被包含的对象可以独立存在。容器会使用该对象,但不会控制它的生命周期。以 Team 和它的 Player 对象为例:即使没有球队,球员也可以存在:
class Team {
private List<Player> players;
public Team() {
players = new ArrayList<>();
}
public void addPlayer(Player player) {
players.add(player); // Team 使用已有的玩家
}
}关键区别:在组合中,容器在内部创建其组成部分。在聚合中,对象从外部传入。删除 Team 时,Player 对象仍然存在。删除 House 时,其中的 Room 对象也会消失。
挑战
简单我们来构建一个大学课程系统,演示聚合和组合。你会看到,Course拥有自己的Lecture对象(组合),而它只引用独立存在的Professor对象(聚合)。
你要把代码分成四个文件:
Professor.java:创建一个表示教授的类,这个教授可以独立于任何课程存在。Professor 有两个私有字段:name(String)和department(String)。添加一个构造函数来初始化这两个字段,并为每个字段添加 getter 方法。重写toString(),使其返回:Prof. [name] ([department])Lecture.java:创建一个表示讲座的类,这种讲座只有在课程中才有意义。Lecture 有两个私有字段:topic(String)和durationMinutes(int)。添加一个构造函数和 getter 方法。重写toString(),使其返回:Lecture: [topic] ([durationMinutes] min)Course.java:在这里演示这两种关系!Course 有三个私有字段:title(String)、professor(Professor,聚合)和lectures(Lecture 对象数组,组合)。构造函数接收课程标题、一个 Professor 对象(从外部传入,聚合)以及讲座数量。在构造函数内部,创建 Lecture 数组,并用新的 Lecture 对象填充数组。对于索引为
i的每个讲座,使用主题"Topic " + (i + 1)和时长45分钟来创建它。这种内部创建体现了组合。添加一个
getInfo()方法,返回多行 String:Course: [title] Instructor: [professor.toString()] Lectures: [number of lectures]还要添加一个
listLectures()方法,返回一个 String,其中每个讲座的 toString() 都单独占一行。Main.java:把所有内容组合起来!你会收到四项输入:教授姓名(String)、教授所属院系(String)、课程标题(String)和讲座数量(int)。首先,使用给定的姓名和院系创建一个 Professor。这个教授独立存在。然后创建一个 Course,传入课程标题、教授(聚合)和讲座数量(课程会在内部创建自己的讲座,也就是组合)。
输出
getInfo()的结果,然后输出一个空行,再输出listLectures()的结果。
你会按顺序收到四项输入:教授姓名、院系、课程标题和讲座数量。
请注意关键区别:Professor 在外部创建并传入 Course(聚合:这位教授可以教授其他课程,也可以在没有这门课程的情况下独立存在)。Lecture 在 Course 构造函数内部创建(组合。它们只属于这门课程,没有这门课程就不会存在)。
亲手试试
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取输入
String professorName = scanner.nextLine();
String department = scanner.nextLine();
String courseTitle = scanner.nextLine();
int numberOfLectures = scanner.nextInt();
// TODO:创建一个 Professor 对象(可独立存在,属于聚合关系)
// TODO:创建一个 Course 对象,并传入 professor(聚合关系)
// 课程会在内部创建自己的讲座(组合关系)
// TODO:输出 getInfo() 的结果
// TODO:输出一个空行
// TODO:输出 listLectures() 的结果
}
}这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Java 在线编译器