Menu
Coddy logo textTech

Агрегация против композиции

Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 48 из 87.

И агрегация, и композиция являются формами отношений «has-a», но они различаются в одном важном аспекте: владение и зависимость жизненного цикла.

При композиции содержащийся объект не может существовать независимо от контейнера. При уничтожении контейнера уничтожаются и его части. Представьте класс 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 удаляется, объекты Player все еще существуют. Когда объект House удаляется, его объекты Room также исчезают.

challenge icon

Задание

Легко

Давайте создадим систему университетских курсов, которая демонстрирует как агрегацию, так и композицию. Вы увидите, как Course владеет своими объектами Lecture (композиция), в то время как он только ссылается на объекты Professor, которые существуют независимо (агрегация).

Вы организуете свой код в четырех файлах:

  • Professor.java: Создайте класс, представляющий профессора, который может существовать независимо от любого курса. У Professor есть два приватных поля: name (String) и department (String). Включите конструктор для инициализации обоих полей и методы-геттеры для каждого. Переопределите toString(), чтобы он возвращал: "Prof. " + name + " (" + department + ")"
  • Lecture.java: Создайте класс, представляющий лекцию, которая имеет смысл только внутри курса. У Lecture есть два приватных поля: topic (String) и durationMinutes (int). Включите конструктор и геттеры. Переопределите toString(), чтобы он возвращал: "Lecture: " + topic + " (" + durationMinutes + " min)"
  • Course.java: Здесь вы продемонстрируете оба типа отношений! У Course есть три приватных поля: title (String), professor (Professor — агрегация) и lectures (массив объектов Lecture — композиция).

    Конструктор принимает название курса, объект Professor (переданный извне — агрегация) и количество лекций. Внутри конструктора создайте массив Lecture и заполните его новыми объектами Lecture. Для каждой лекции с индексом i создайте её с темой "Topic " + (i + 1) и продолжительностью 45 минут. Это внутреннее создание демонстрирует композицию.

    Добавьте метод getInfo(), который возвращает многострочную строку:

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

    Также добавьте метод listLectures(), который возвращает строку, где toString() каждой лекции находится на отдельной строке.

  • Main.java: Соберите всё вместе! Вы получите четыре входных значения: имя профессора (String), кафедра профессора (String), название курса (String) и количество лекций (int).

    Сначала создайте объект Professor с заданным именем и кафедрой — этот профессор существует независимо. Затем создайте Course, передав название, профессора (агрегация) и количество лекций (курс создаст свои лекции внутри себя — композиция).

    Выведите результат getInfo(), затем выведите пустую строку, а затем выведите результат listLectures().

Вы получите четыре входных значения по порядку: имя профессора, кафедра, название курса и количество лекций.

Обратите внимание на ключевое различие: Professor создается извне и передается в Course (агрегация — профессор может преподавать другие курсы или существовать без этого). Объекты Lecture создаются внутри конструктора Course (композиция — они принадлежат исключительно этому курсу и не существовали бы без него).

Шпаргалка

Как агрегация, так и композиция являются отношениями типа «has-a» (имеет), которые различаются владением и зависимостью жизненного цикла.

Композиция: содержащийся объект не может существовать независимо от контейнера. Когда контейнер уничтожается, его части также уничтожаются. Контейнер создает свои части внутри себя.

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 создает комнаты и владеет ими
        }
    }
}

Агрегация: содержащийся объект может существовать независимо. Контейнер использует объект, но не управляет его жизненным циклом. Объекты передаются извне.

class Team {
    private List<Player> players;
    
    public Team() {
        players = new ArrayList<>();
    }
    
    public void addPlayer(Player player) {
        players.add(player);  // Team использует существующих игроков
    }
}

Ключевое отличие: при удалении контейнера агрегированные объекты продолжают существовать, а композитные объекты уничтожаются.

Попробуйте сами

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, передав профессора (агрегация)
        // Курс будет создавать свои собственные лекции внутри (композиция)
        
        // TODO: Вывести результат getInfo()
        
        // TODO: Вывести пустую строку
        
        // TODO: Вывести результат listLectures()
        
    }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование