Menu
Coddy logo textTech

Agregación vs. Composición

Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy — lección 48 de 87.

Tanto la agregación como la composición son formas de relaciones "has-a", pero difieren en un aspecto crucial: la propiedad y la dependencia del ciclo de vida.

En la composición, el objeto contenido no puede existir independientemente del contenedor. Cuando el contenedor se destruye, también lo hacen sus partes. Piense en una House y sus objetos Room: las habitaciones no existen sin la casa:

class House {
    private Room[] rooms;
    
    public House(int numRooms) {
        rooms = new Room[numRooms];
        for (int i = 0; i < numRooms; i++) {
            rooms[i] = new Room();  // La casa crea y es dueña de las habitaciones
        }
    }
}

En la agregación, el objeto contenido puede existir de forma independiente. El contenedor utiliza el objeto pero no controla su ciclo de vida. Considera un Team y sus objetos Player; los jugadores existen incluso sin un equipo:

class Team {
    private List<Player> players;
    
    public Team() {
        players = new ArrayList<>();
    }
    
    public void addPlayer(Player player) {
        players.add(player);  // El equipo utiliza jugadores existentes
    }
}

La distinción clave: en la composición, el contenedor crea sus partes internamente. En la agregación, los objetos se pasan desde el exterior. Cuando se elimina un Team, los objetos Player aún existen. Cuando se elimina una House, sus objetos Room también desaparecen.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de cursos universitarios que demuestre tanto la agregación como la composición. Verás cómo un Course posee sus objetos Lecture (composición), mientras que solo hace referencia a objetos Professor que existen de forma independiente (agregación).

Organizarás tu código en cuatro archivos:

  • Professor.java: Crea una clase que represente a un profesor que puede existir independientemente de cualquier curso. Un Professor tiene dos campos privados: name (String) y department (String). Incluye un constructor para inicializar ambos campos y métodos getter para cada uno. Sobrescribe toString() para que devuelva: "Prof. " + name + " (" + department + ")"
  • Lecture.java: Crea una clase que represente una lección que solo tiene sentido dentro de un curso. Una Lecture tiene dos campos privados: topic (String) y durationMinutes (int). Incluye un constructor y getters. Sobrescribe toString() para que devuelva: "Lecture: " + topic + " (" + durationMinutes + " min)"
  • Course.java: ¡Aquí es donde demostrarás ambas relaciones! Un Course tiene tres campos privados: title (String), professor (Professor - agregación) y lectures (un arreglo de objetos Lecture - composición).

    El constructor recibe el título del curso, un objeto Professor (pasado desde el exterior - agregación) y el número de lecciones. Dentro del constructor, crea el arreglo de Lecture y llénalo con nuevos objetos Lecture. Para cada lección en el índice i, créala con el tema "Topic " + (i + 1) y una duración de 45 minutos. Esta creación interna demuestra la composición.

    Añade un método getInfo() que devuelva un String multilínea:

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

    También añade un método listLectures() que devuelva un String con el toString() de cada lección en su propia línea.

  • Main.java: ¡Une todo! Recibirás cuatro entradas: nombre del profesor (String), departamento del profesor (String), título del curso (String) y número de lecciones (int).

    Primero, crea un Professor con el nombre y departamento dados; este profesor existe de forma independiente. Luego crea un Course, pasando el título, el profesor (agregación) y el recuento de lecciones (el curso creará sus propias lecciones internamente - composición).

    Imprime el resultado de getInfo(), luego imprime una línea vacía y después imprime el resultado de listLectures().

Recibirás cuatro entradas en orden: nombre del profesor, departamento, título del curso y número de lecciones.

Observa la diferencia clave: el Professor se crea fuera y se pasa al Course (agregación: el profesor podría impartir otros cursos o existir sin este). Las Lectures se crean dentro del constructor de Course (composición: pertenecen exclusivamente a este curso y no existirían sin él).

Hoja de referencia

Tanto la agregación como la composición son relaciones de tipo "tiene un" (has-a) que difieren en la propiedad y la dependencia del ciclo de vida.

Composición: El objeto contenido no puede existir independientemente del contenedor. Cuando el contenedor se destruye, sus partes también se destruyen. El contenedor crea sus partes internamente.

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 crea y posee las habitaciones
        }
    }
}

Agregación: El objeto contenido puede existir de forma independiente. El contenedor utiliza el objeto pero no controla su ciclo de vida. Los objetos se pasan desde el exterior.

class Team {
    private List<Player> players;
    
    public Team() {
        players = new ArrayList<>();
    }
    
    public void addPlayer(Player player) {
        players.add(player);  // Team utiliza jugadores existentes
    }
}

Distinción clave: Cuando se elimina un contenedor, los objetos agregados siguen existiendo, pero los objetos compuestos se destruyen.

Pruébalo tú mismo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Leer entradas
        String professorName = scanner.nextLine();
        String department = scanner.nextLine();
        String courseTitle = scanner.nextLine();
        int numberOfLectures = scanner.nextInt();
        
        // TODO: Crear un objeto Professor (existe independientemente - agregación)
        
        // TODO: Crear un objeto Course, pasando el profesor (agregación)
        // El curso creará sus propias lecciones internamente (composición)
        
        // TODO: Imprimir el resultado de getInfo()
        
        // TODO: Imprimir una línea vacía
        
        // TODO: Imprimir el resultado de listLectures()
        
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos