Agregação vs Composição
Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy — lição 48 de 87.
Tanto a agregação quanto a composição são formas de relacionamentos "has-a", mas elas diferem em um aspecto crucial: propriedade e dependência de ciclo de vida.
Na composição, o objeto contido não pode existir independentemente do contêiner. Quando o contêiner é destruído, suas partes também são. Pense em uma House e seus objetos Room—os quartos não existem sem a 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(); // A casa cria e possui os cômodos
}
}
}Na agregação, o objeto contido pode existir de forma independente. O contêiner usa o objeto, mas não controla seu ciclo de vida. Considere um Team e seus objetos Player — os jogadores existem mesmo sem um time:
class Team {
private List<Player> players;
public Team() {
players = new ArrayList<>();
}
public void addPlayer(Player player) {
players.add(player); // A equipe usa jogadores existentes
}
}A distinção fundamental: na composição, o contêiner cria suas partes internamente. Na agregação, os objetos são passados de fora. Quando um Team é excluído, os objetos Player ainda existem. Quando uma House é excluída, seus objetos Room também desaparecem.
Desafio
FácilVamos construir um sistema de cursos universitários que demonstra tanto agregação quanto composição. Você verá como um Course possui seus objetos Lecture (composição), enquanto apenas referencia objetos Professor que existem de forma independente (agregação).
Você organizará seu código em quatro arquivos:
Professor.java: Crie uma classe que representa um professor que pode existir independentemente de qualquer curso. Um Professor possui dois campos privados:name(String) edepartment(String). Inclua um construtor para inicializar ambos os campos e métodos getter para cada um. SobrescrevatoString()para retornar:"Prof. " + name + " (" + department + ")"Lecture.java: Crie uma classe que representa uma palestra que só faz sentido dentro de um curso. Uma Lecture possui dois campos privados:topic(String) edurationMinutes(int). Inclua um construtor e getters. SobrescrevatoString()para retornar:"Lecture: " + topic + " (" + durationMinutes + " min)"Course.java: É aqui que você demonstrará ambos os relacionamentos! Um Course possui três campos privados:title(String),professor(Professor - agregação) electures(um array de objetos Lecture - composição).O construtor recebe o título do curso, um objeto Professor (passado de fora - agregação) e o número de palestras. Dentro do construtor, crie o array de Lecture e preencha-o com novos objetos Lecture. Para cada palestra no índice
i, crie-a com o tópico"Topic " + (i + 1)e duração de45minutos. Essa criação interna demonstra composição.Adicione um método
getInfo()que retorna uma String de várias linhas:Course: [title] Instructor: [professor.toString()] Lectures: [number of lectures]Adicione também um método
listLectures()que retorna uma String com o toString() de cada palestra em sua própria linha.Main.java: Reúna tudo! Você receberá quatro entradas: nome do professor (String), departamento do professor (String), título do curso (String) e número de palestras (int).Primeiro, crie um Professor com o nome e departamento fornecidos — este professor existe de forma independente. Em seguida, crie um Course, passando o título, o professor (agregação) e a contagem de palestras (o curso criará suas próprias palestras internamente - composição).
Imprima o resultado de
getInfo(), depois imprima uma linha vazia e, em seguida, imprima o resultado delistLectures().
Você receberá quatro entradas na ordem: nome do professor, departamento, título do curso e número de palestras.
Observe a diferença fundamental: o Professor é criado fora e passado para o Course (agregação — o professor poderia dar outros cursos ou existir sem este). As Lectures são criadas dentro do construtor do Course (composição — elas pertencem exclusivamente a este curso e não existiriam sem ele).
Folha de consulta
Tanto a agregação quanto a composição são relacionamentos do tipo "tem-um" que diferem na propriedade e na dependência do ciclo de vida.
Composição: O objeto contido não pode existir independentemente do contêiner. Quando o contêiner é destruído, suas partes também são destruídas. O contêiner cria suas 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 cria e possui os quartos
}
}
}Agregação: O objeto contido pode existir independentemente. O contêiner usa o objeto, mas não controla seu ciclo de vida. Os objetos são passados de fora.
class Team {
private List<Player> players;
public Team() {
players = new ArrayList<>();
}
public void addPlayer(Player player) {
players.add(player); // Team usa jogadores existentes
}
}Distinção principal: Quando um contêiner é excluído, os objetos agregados ainda existem, mas os objetos compostos são destruídos.
Experimente você mesmo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Ler entradas
String professorName = scanner.nextLine();
String department = scanner.nextLine();
String courseTitle = scanner.nextLine();
int numberOfLectures = scanner.nextInt();
// TODO: Criar um objeto Professor (existe independentemente - agregação)
// TODO: Criar um objeto Course, passando o professor (agregação)
// O curso criará suas próprias palestras internamente (composição)
// TODO: Imprimir o resultado de getInfo()
// TODO: Imprimir uma linha vazia
// TODO: Imprimir o resultado de listLectures()
}
}Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosA Palavra-chave thisMétodosCampos (Atributos)Método ConstrutorSobrecarga de ConstrutorRecapitulação - Calculadora Simples4Herança
Herança Básica (extends)A Palavra-chave superSobrescrita de Método (@Override)Encadeamento de ConstrutoresA Classe ObjectHerança Simples e MultinívelPor que não há Herança Múltipla de ClassesRecapitulação - Hierarquia de Funcionários7Métodos Especiais e a Classe Object
Método toString()equals() e hashCode()Método clone()compareTo() e ComparableInterface ComparatorRecapitulação - Ordenação Personalizada2Modificadores de Acesso e Encapsulamento
Visão Geral dos Níveis de AcessoMétodos Getter e SetterOcultação de InformaçõesA Palavra-chave finalRecapitulação - Gerenciador de Conta Bancária5Polimorfismo
Fundamentos de Sobrecarga de MétodosSobrescrita de Métodos (Tempo de Execução)Upcasting e DowncastingO Operador instanceofClasses e Métodos AbstratosRecapitulação - Calculadora de Formas8Conceitos Avançados de OOP
Composição vs HerançaAgregação vs ComposiçãoClasses Internas, Aninhadas e AnônimasEnums e Métodos de EnumRecords (Java 16+)Classes Seladas (Java 17+)11Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão BuilderPadrão ObserverPadrão Strategy3Propriedades de Classe e Membros Estáticos
Variáveis de Instância vs EstáticasMétodos EstáticosBlocos EstáticosConstantes (static final)Recapitulação - Contador e Utilitário6Interfaces e Classes Abstratas
Introdução às InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesDefault e Static em InterfacesClasses Abstratas vs InterfacesInterfaces FuncionaisRecapitulação - Sistema de Pagamento9Generics
Introdução a GenericsClasses GenéricasMétodos GenéricosParâmetros de Tipos DelimitadosWildcards (?, extends, super)Recapitulação - Container Genérico12Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Iterator