Menu
CoddyTech

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

Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy. Урок 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 тоже исчезают.

challenge icon

Задание

Легко

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

Вы распределите код по четырём файлам:

  • Professor.java: Создайте класс, представляющий профессора, который может существовать независимо от любого курса. У профессора есть два приватных поля: name (String) и department (String). Добавьте конструктор для инициализации обоих полей и методы получения значений для каждого из них. Переопределите toString(), чтобы он возвращал: Prof. [name] ([department])
  • Lecture.java: Создайте класс, представляющий лекцию, которая имеет смысл только в рамках курса. У лекции есть два приватных поля: topic (String) и durationMinutes (int). Добавьте конструктор и методы получения значений. Переопределите toString(), чтобы он возвращал: Lecture: [topic] ([durationMinutes] min)
  • Course.java: Именно здесь вы продемонстрируете оба типа связей! У курса есть три приватных поля: 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 (агрегация: профессор может вести другие курсы или существовать без этого курса). Lectures создаются внутри конструктора 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, передав ему профессора (агрегация)
        // Курс создаст собственные лекции внутри себя (композиция)
        
        // TODO: Вывести результат getInfo()
        
        // TODO: Вывести пустую строку
        
        // TODO: Вывести результат listLectures()
        
    }
}
quiz iconПроверьте себя

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

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

Потренируйтесь самостоятельно: Онлайн-компилятор Java