Menu
Coddy logo textTech

어그리게이션 vs 컴포지션

Coddy Java 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 87개 중 48번째.

집합(Aggregation)과 합성(Composition)은 모두 "has-a" 관계의 형태이지만, 한 가지 중요한 측면에서 차이가 있습니다: 소유권과 생명주기 의존성입니다.

합성(composition)에서, 포함된 객체는 컨테이너와 독립적으로 존재할 수 없습니다. 컨테이너가 소멸될 때 그 하위 요소들도 함께 소멸됩니다. 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가 Room들을 생성하고 소유합니다
        }
    }
}

집약(aggregation) 관계에서, 포함된 객체는 독립적으로 존재할 수 있습니다. 컨테이너는 객체를 사용하지만 그 생명주기를 제어하지는 않습니다. Team과 그 Player 객체들을 생각해 보세요. 선수들은 팀이 없어도 존재합니다:

class Team {
    private List<Player> players;
    
    public Team() {
        players = new ArrayList<>();
    }
    
    public void addPlayer(Player player) {
        players.add(player);  // Team은 기존 Player들을 사용합니다
    }
}

핵심적인 차이점은 다음과 같습니다. 합성(composition)에서는 컨테이너가 내부적으로 부품을 생성합니다. 집약(aggregation)에서는 객체가 외부에서 전달됩니다. Team이 삭제되어도 Player 객체는 여전히 존재합니다. House가 삭제되면 그 안의 Room 객체들도 함께 사라집니다.

challenge icon

챌린지

쉬움

집계(aggregation)와 구성(composition)을 모두 보여주는 대학 강의 시스템을 구축해 보겠습니다. CourseLecture 객체를 소유하는 방식(구성)과, 독립적으로 존재하는 Professor 객체를 단순히 참조하는 방식(집계)의 차이를 배우게 됩니다.

코드는 네 개의 파일로 구성됩니다:

  • Professor.java: 어떤 강의와도 독립적으로 존재할 수 있는 교수를 나타내는 클래스를 생성합니다. Professor는 두 개의 private 필드 name (String)과 department (String)를 가집니다. 두 필드를 초기화하는 생성자와 각 필드에 대한 getter 메서드를 포함하세요. toString()을 오버라이드하여 "Prof. " + name + " (" + department + ")" 형식을 반환하도록 합니다.
  • Lecture.java: 강의 내에서만 의미가 있는 수업(lecture)을 나타내는 클래스를 생성합니다. Lecture는 두 개의 private 필드 topic (String)과 durationMinutes (int)를 가집니다. 생성자와 getter를 포함하세요. toString()을 오버라이드하여 "Lecture: " + topic + " (" + durationMinutes + " min)" 형식을 반환하도록 합니다.
  • Course.java: 여기서 두 가지 관계를 모두 보여줍니다! Course는 세 개의 private 필드 title (String), professor (Professor - 집계), 그리고 lectures (Lecture 객체 배열 - 구성)를 가집니다.

    생성자는 강의 제목(title), Professor 객체(외부에서 전달됨 - 집계), 그리고 강의 수(number of lectures)를 매개변수로 받습니다. 생성자 내부에서 Lecture 배열을 생성하고 새로운 Lecture 객체들로 채웁니다. 인덱스 i에 있는 각 강의에 대해, 주제는 "Topic " + (i + 1)로, 기간은 45분으로 설정하여 생성합니다. 이 내부적인 생성이 구성을 보여줍니다.

    다음과 같은 여러 줄의 문자열을 반환하는 getInfo() 메서드를 추가하세요:

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

    또한 각 강의의 toString() 결과를 각각 별도의 줄에 포함하는 문자열을 반환하는 listLectures() 메서드를 추가하세요.

  • Main.java: 모든 것을 하나로 합칩니다! 교수 이름 (String), 교수 학과 (String), 강의 제목 (String), 강의 수 (int)의 네 가지 입력을 받습니다.

    먼저, 주어진 이름과 학과로 Professor 객체를 생성합니다. 이 교수는 독립적으로 존재합니다. 그런 다음 제목, 교수 객체(집계), 강의 수(강의는 내부적으로 자신의 수업들을 생성함 - 구성)를 전달하여 Course 객체를 생성합니다.

    getInfo()의 결과를 출력하고, 빈 줄을 하나 출력한 다음, listLectures()의 결과를 출력하세요.

교수 이름, 학과, 강의 제목, 강의 수 순서대로 네 개의 입력을 받게 됩니다.

핵심적인 차이점에 주목하세요: Professor는 외부에서 생성되어 Course로 전달됩니다(집계 — 교수는 다른 강의를 가르칠 수도 있고 이 강의 없이도 존재할 수 있습니다). Lectures는 Course 생성자 내부에서 생성됩니다(구성 — 이들은 오직 이 강의에만 속하며 강의 없이는 존재하지 않습니다).

치트 시트

집합(Aggregation)합성(Composition)은 모두 소유권과 생명주기 의존성이 다른 "has-a" 관계입니다.

합성(Composition): 포함된 객체는 컨테이너와 독립적으로 존재할 수 없습니다. 컨테이너가 소멸될 때 그 구성 요소들도 함께 소멸됩니다. 컨테이너는 내부적으로 구성 요소들을 생성합니다.

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가 방들을 생성하고 소유합니다
        }
    }
}

집합(Aggregation): 포함된 객체는 독립적으로 존재할 수 있습니다. 컨테이너는 객체를 사용하지만 그 생명주기를 제어하지는 않습니다. 객체는 외부에서 전달됩니다.

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: Professor를 전달하여 Course 객체 생성 (집합 관계)
        // Course는 내부적으로 자체 강의를 생성함 (합성 관계)
        
        // TODO: getInfo() 결과 출력
        
        // TODO: 빈 줄 출력
        
        // TODO: listLectures() 결과 출력
        
    }
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨