Menu
CoddyTech

Kết tập và hợp thành

Thuộc phần Lập trình hướng đối tượng trong hành trình Java của Coddy. Bài học 48 trên 87.

Cả kết tập lẫn hợp thành đều là dạng quan hệ “có”, nhưng chúng khác nhau ở một khía cạnh then chốt: quyền sở hữu và sự phụ thuộc về vòng đời.

Trong quan hệ hợp thành, đối tượng thành phần không thể tồn tại độc lập với đối tượng chứa nó. Khi đối tượng chứa bị hủy, các thành phần của nó cũng bị hủy. Hãy nghĩ đến một House và các đối tượng Room của nó: các phòng không tồn tại nếu không có ngôi nhà:

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 tạo và sở hữu rooms
        }
    }
}

Trong quan hệ kết tập, đối tượng được chứa có thể tồn tại độc lập. Đối tượng chứa sử dụng đối tượng đó nhưng không kiểm soát vòng đời của nó. Hãy xem xét một Team và các đối tượng Player của nó: người chơi vẫn tồn tại ngay cả khi không có đội:

class Team {
    private List<Player> players;
    
    public Team() {
        players = new ArrayList<>();
    }
    
    public void addPlayer(Player player) {
        players.add(player);  // Team sử dụng những người chơi đã có
    }
}

Điểm khác biệt chính: trong quan hệ hợp thành, đối tượng chứa tự tạo các thành phần bên trong. Trong quan hệ kết tập, các đối tượng được truyền từ bên ngoài vào. Khi Team bị xóa, các đối tượng Player vẫn tồn tại. Khi House bị xóa, các đối tượng Room cũng biến mất.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống khóa học đại học thể hiện cả quan hệ kết tập và hợp thành. Bạn sẽ thấy một Course sở hữu các đối tượng Lecture (hợp thành), còn đối với các đối tượng Professor, lớp này chỉ tham chiếu đến chúng vì chúng tồn tại độc lập (kết tập).

Bạn sẽ sắp xếp code trong bốn tệp:

  • Professor.java: Tạo một lớp đại diện cho giáo sư có thể tồn tại độc lập với mọi khóa học. Một Professor có hai trường riêng tư: name (String) và department (String). Thêm hàm khởi tạo để khởi tạo cả hai trường cùng các phương thức getter cho từng trường. Ghi đè toString() để trả về: Prof. [name] ([department])
  • Lecture.java: Tạo một lớp đại diện cho bài giảng chỉ có ý nghĩa trong một khóa học. Một Lecture có hai trường riêng tư: topic (String) và durationMinutes (int). Thêm hàm khởi tạo và các phương thức getter. Ghi đè toString() để trả về: Lecture: [topic] ([durationMinutes] min)
  • Course.java: Đây là nơi bạn thể hiện cả hai mối quan hệ! Một Course có ba trường riêng tư: title (String), professor (Professor, kết tập) và lectures (mảng các đối tượng Lecture, hợp thành).

    Hàm khởi tạo nhận tiêu đề khóa học, một đối tượng Professor (được truyền từ bên ngoài, kết tập) và số lượng bài giảng. Bên trong hàm khởi tạo, hãy tạo mảng Lecture rồi điền các đối tượng Lecture mới vào mảng. Với mỗi bài giảng ở chỉ số i, hãy tạo bài giảng với chủ đề "Topic " + (i + 1) và thời lượng 45 phút. Việc tạo các đối tượng này bên trong thể hiện quan hệ hợp thành.

    Thêm phương thức getInfo() trả về một chuỗi String gồm nhiều dòng:

    Course: [title]
    Instructor: [professor.toString()]
    Lectures: [number of lectures]

    Đồng thời, thêm phương thức listLectures() trả về một chuỗi String, trong đó kết quả toString() của từng bài giảng nằm trên một dòng riêng.

  • Main.java: Kết hợp mọi thứ lại với nhau! Bạn sẽ nhận bốn đầu vào: tên giáo sư (String), khoa của giáo sư (String), tiêu đề khóa học (String) và số lượng bài giảng (int).

    Trước tiên, hãy tạo một Professor với tên và khoa đã cho. Giáo sư này tồn tại độc lập. Sau đó, tạo một Course, truyền vào tiêu đề, giáo sư (kết tập) và số lượng bài giảng (khóa học sẽ tự tạo các bài giảng bên trong, hợp thành).

    In kết quả của getInfo(), sau đó in một dòng trống, rồi in kết quả của listLectures().

Bạn sẽ nhận bốn đầu vào theo thứ tự: tên giáo sư, khoa, tiêu đề khóa học và số lượng bài giảng.

Lưu ý điểm khác biệt chính: Professor được tạo bên ngoài rồi truyền vào Course (kết tập: giáo sư có thể dạy các khóa học khác hoặc tồn tại mà không cần khóa học này). Lecture được tạo bên trong hàm khởi tạo Course (hợp thành). Chúng chỉ thuộc về khóa học này và sẽ không tồn tại nếu thiếu khóa học đó.

Tự làm thử

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Đọc các giá trị đầu vào
        String professorName = scanner.nextLine();
        String department = scanner.nextLine();
        String courseTitle = scanner.nextLine();
        int numberOfLectures = scanner.nextInt();
        
        // TODO: Tạo đối tượng Professor (tồn tại độc lập, quan hệ kết tập)
        
        // TODO: Tạo đối tượng Course, truyền đối tượng Professor vào (quan hệ kết tập)
        // Course sẽ tự tạo các buổi học bên trong (quan hệ hợp thành)
        
        // TODO: In ra kết quả của getInfo()
        
        // TODO: In ra một dòng trống
        
        // TODO: In ra kết quả của listLectures()
        
    }
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Java online