9  Classes e objetos

Reunir estado, comportamento e invariantes

9.1 Objetivos de aprendizagem

Ao concluir este capítulo, você deverá ser capaz de:

  • diferenciar classe, objeto, atributo e método;
  • inicializar objetos com construtores;
  • usar this para distinguir atributo e parâmetro;
  • proteger o estado com private;
  • representar regras por operações, não por setters genéricos.

9.2 Estado e comportamento

A classe Chatbot origina dois objetos, cada um com um nome e um histórico próprios.

A classe define; cada objeto mantém seu próprio estado.

Uma classe define a estrutura e as operações disponíveis. Um objeto é uma instância concreta dessa classe. Seus atributos formam o estado; seus métodos definem comportamentos.

class ContaPontos {
    private int saldo;

    public ContaPontos(int saldoInicial) {
        if (saldoInicial < 0) {
            throw new IllegalArgumentException("Saldo inicial inválido.");
        }
        this.saldo = saldoInicial;
    }

    public void creditar(int valor) {
        if (valor <= 0) {
            throw new IllegalArgumentException("O crédito deve ser positivo.");
        }
        saldo += valor;
    }

    public boolean debitar(int valor) {
        if (valor <= 0 || valor > saldo) {
            return false;
        }
        saldo -= valor;
        return true;
    }

    public int getSaldo() {
        return saldo;
    }
}

A validação de valor <= 0 é indispensável: sem ela, subtrair um valor negativo aumentaria o saldo. O atributo privado só pode mudar por operações que preservam as regras.

9.3 Construtores e this

Um estudante tenta conversar com o projeto de um robô e aprende que precisa criar uma instância.

Quadrinho: classe não é objeto.

O construtor cria um estado inicial válido. this.nome indica o atributo do objeto atual, enquanto nome representa o parâmetro:

class Chatbot {
    private final String nome;

    public Chatbot(String nome) {
        if (nome == null || nome.isBlank()) {
            throw new IllegalArgumentException("Nome obrigatório.");
        }
        this.nome = nome.strip();
    }
}

final impede que a referência seja reatribuída depois da construção.

9.4 Classe do chatbot

import java.util.ArrayList;
import java.util.List;

class ChatbotBasico {
    private final String nome;
    private final List<String> historico = new ArrayList<>();

    ChatbotBasico(String nome) {
        if (nome == null || nome.isBlank()) {
            throw new IllegalArgumentException("Nome obrigatório.");
        }
        this.nome = nome.strip();
    }

    String responder(String mensagem) {
        if (mensagem == null || mensagem.isBlank()) {
            return "Digite uma mensagem.";
        }
        historico.add(mensagem.strip());
        return nome + ": recebi sua mensagem.";
    }

    List<String> consultarHistorico() {
        return List.copyOf(historico);
    }
}

public class Capitulo08Classes {
    public static void main(String[] args) {
        ChatbotBasico bot = new ChatbotBasico("TutorJavaBot");
        System.out.println(bot.responder("oi"));
        System.out.println(bot.consultarHistorico());
    }
}

A cópia devolvida por consultarHistorico impede alteração externa da lista interna.

9.5 Composição inicial

Composição representa uma relação “tem um”. Um chatbot pode ter um objeto responsável pelo histórico; uma turma pode ter uma lista de alunos. Quando a responsabilidade crescer, mover o histórico para uma classe própria evita que o chatbot concentre trabalho demais.

9.6 Evolução do projeto: versão 8

Transforme variáveis e métodos isolados em um objeto ChatbotBasico. O main cria o objeto e coordena entrada e saída; a classe protege nome, histórico e regras de resposta.

O exemplo completo está em examples/src/Capitulo08Classes.java.

9.7 Prática verificável

  1. Acrescente o método totalMensagens().
  2. Rejeite nomes vazios no construtor.
  3. Confirme que a lista devolvida não pode alterar o histórico interno.
  4. Explique qual invariante cada validação protege.
NotaInvariante

Uma invariante é uma condição que deve permanecer verdadeira durante toda a vida do objeto, como “o nome do chatbot não é vazio”.