Professor Muniz Educação & Programação

Trilha: Estrutura de Dados

Voltar aos conteúdos
Apostila de Apoio Didático

Pilares de Orientação a Objetos em Java

Guia Completo sobre Visibilidade, Encapsulamento, Alta Coesão e Relacionamentos entre Objetos

MÓDULO 1

Visibilidade e Modificadores de Acesso

Os objetos em Java encapsulam atributos e comportamentos. O acesso direto e indiscriminado às propriedades internas de um objeto é uma prática arriscada, pois impede a validação de regras de negócio.

Para gerenciar a visibilidade e proteger o estado de nossas classes, utilizamos os modificadores de acesso:

Modificador Símbolo UML Descrição e Nível de Acesso
public + Livre acesso para qualquer classe em qualquer pacote do sistema.
private - Acessível única e exclusivamente pelos métodos de dentro da própria classe.
protected # Acessível por classes do mesmo pacote e classes filhas (através de herança).
default (sem palavra-chave) Nenhum Acessível apenas por classes declaradas no mesmo pacote físico.
MÓDULO 2

Encapsulamento, Métodos Especiais e Alta Coesão

2.1 O que é Encapsulamento?

O **encapsulamento** consiste em ocultar os detalhes de implementação e o estado interno de uma classe, expondo apenas uma interface pública de métodos. Definimos os atributos como `private` e controlamos sua leitura/escrita por meio de métodos especiais: **Getters** (leitura) e **Setters** (escrita).

Conceito Visual de Encapsulamento Barreira de Segurança: Getters/Setters controlando o acesso a atributos Privados

2.2 O Conceito de Alta Coesão

Uma classe possui alta coesão quando é extremamente focada e tem uma única responsabilidade. As validações das regras de negócio devem ocorrer dentro dela mesma. Se permitirmos que classes externas alterem ou façam as validações do nosso objeto, criamos dependências acopladas e perigosas (baixa coesão).

Exemplo Prático: Validação Interna com Construtores Coesos

Observe no código abaixo que o construtor chama o método `setIdade()` em vez de atribuir o valor diretamente. Isso garante que a validação de barreira seja executada mesmo na instanciação:

public class Paciente {
    private int idade; // Atributo protegido (private)

    // Construtor vazio
    public Paciente() {
    }

    // Construtor parametrizado chamando o setter para aplicar a regra
    public Paciente(int idade) {
        this.setIdade(idade);
    }

    // Getter tradicional
    public int getIdade() {
        return this.idade;
    }

    // Setter com validação interna (Alta Coesão)
    public void setIdade(int idade) {
        if (idade <= 0 || idade > 120) {
            System.out.println("[Alerta] Idade inválida de paciente ignorada!");
            this.idade = 1; // Valor padrão de consistência
        } else {
            this.idade = idade;
        }
    }
}
MÓDULO 3

Associação Simples (1 para 1)

Uma nova classe em Java funciona como um tipo de dado personalizado. O relacionamento de **associação** ocorre quando usamos instâncias de uma classe como atributos internos de outra.

Imagine uma classe `Sorvete` que possui uma associação de um-para-um com a classe `Calda`:

// Classe auxiliar
public class Calda {
    private String sabor;
    
    public Calda(String sabor) {
        this.sabor = sabor;
    }
    public String getSabor() { return this.sabor; }
}

// Classe Principal com associação 1-1
public class Sorvete {
    private String saborSorvete;
    private Calda caldaAdicionada; // Associação 1-1

    public Sorvete(String saborSorvete) {
        this.saborSorvete = saborSorvete;
    }

    public Calda getCalda() { return this.caldaAdicionada; }
    public void setCalda(Calda calda) { this.caldaAdicionada = calda; }
}
MÓDULO 4

Associação de Um para Muitos com ArrayList

Quando precisamos expandir a relação para permitir múltiplos objetos associados (ex: um sorvete com várias caldas), recorremos a coleções dinâmicas como o `ArrayList` da biblioteca padrão do Java.

Regra de Ouro do ArrayList

Por se tratar de um objeto complexo, um `ArrayList` **deve ser obrigatoriamente instanciado** no construtor da classe proprietária. Se você esquecer essa inicialização, tentar acessar um membro de uma referência `null` causará um erro em tempo de execução do tipo NullPointerException.
import java.util.ArrayList; // Importação da estrutura dinâmica

public class SorveteCompleto {
    private String sabor;
    private ArrayList<Calda> caldas; // Associação de 1 para N

    public SorveteCompleto(String sabor) {
        this.sabor = sabor;
        // Instanciação preventiva do objeto lista no construtor
        this.caldas = new ArrayList<Calda>();
    }

    public String getSabor() {
        return this.sabor;
    }

    // Setter adaptado para inserção unitária de objetos
    public void adicionarCalda(Calda calda) {
        this.caldas.add(calda);
    }

    public ArrayList<Calda> getCaldas() {
        return this.caldas;
    }
}
MÓDULO 5

Manipulação e Iteração com For-Each

Para recuperar e iterar de forma limpa e legível os elementos armazenados dentro de uma coleção de objetos, utilizamos a simplificada estrutura do laço for-each:

public class AppSorveteria {
    public static void main(String[] args) {
        SorveteCompleto sorvete = new SorveteCompleto("Baunilha");

        // Instanciando caldas e associando ao sorvete
        sorvete.adicionarCalda(new Calda("Chocolate"));
        sorvete.adicionarCalda(new Calda("Morango"));

        System.out.println("Sorvete de: " + sorvete.getSabor());
        System.out.println("Caldas Adicionadas:");

        // Laço for-each para percorrer a coleção associada
        for (Calda c : sorvete.getCaldas()) {
            System.out.println("- Sabor da calda: " + c.getSabor());
        }
    }
}
MÓDULO 6

Prática de Laboratório (Mãos à Obra!)

Desafio Prático: O Carrinho de Compras

Modele e implemente em Java a relação entre um `Carrinho` de compras e os seus `Itens` (com nome do produto e preço). Use encapsulamento completo e uma associação de 1-para-Muitos.

Requisitos de Desenvolvimento:
  1. Crie a classe `Item` com atributos `nome` (String) e `preco` (double), com construtor e getters.
  2. Crie a classe `Carrinho` que contém uma lista de itens (`ArrayList<Item>`).
  3. Garanta a instanciação da lista no construtor da classe `Carrinho`.
  4. Crie um método `adicionarItem(Item item)` e um método `calcularTotal()` que varre a lista somando o preço de cada item e retorna o total acumulado.
Gabarito Recomendado de Resolução:
// Item.java
public class Item {
    private String nome;
    private double preco;

    public Item(String nome, double preco) {
        this.nome = nome;
        this.preco = preco;
    }

    public String getNome() { return this.nome; }
    public double getPreco() { return this.preco; }
}

// Carrinho.java
import java.util.ArrayList;

public class Carrinho {
    private ArrayList<Item> itens;

    public Carrinho() {
        this.itens = new ArrayList<Item>(); // Instanciação protetiva
    }

    public void adicionarItem(Item item) {
        this.itens.add(item);
    }

    public double calcularTotal() {
        double total = 0.0;
        for (Item item : this.itens) {
            total += item.getPreco();
        }
        return total;
    }
}

Mapeamento Finalizado

Este módulo de encapsulamento e associação estabelece as bases lógicas necessárias para compreender a alocação dinâmica e referências de memória. Na próxima aula de laboratório, estudaremos a estrutura sequencial de **Pilhas**.

Materiais Complementares de Apoio

Slides da Aula: Encapsulamento & Associação

Acesse o slide de apoio didático contendo toda a parte teórica sobre visibilidade, getters/setters e a introdução ao ArrayList em Java.

Baixar Slides
Videoaula Relacionada: Encapsulamento e Relacionamentos

Assista à explicação em vídeo focada em modificadores de acesso, coesão de classes e associações simples e múltiplas.

Assistir Vídeo
Repositório de Código Fonte

Explore, acesse e faça o download de todos os códigos-fonte de exemplo e exercícios estruturados nesta trilha.

Abrir Repositório
Voltar aos conteúdos