13  Introdução a POO

Aqui nasce a mentalidade orientada a objetos: modelar o mundo em classes e objetos.

DicaAbertura narrativa

Todo bom programador evolui mais rápido quando entende por que um tema importa antes de memorizar sintaxe. Neste capítulo, vamos conectar conceito, contexto e prática para transformar teoria em habilidade real.

Programar bem não é decorar comandos: é aprender a organizar ideias. A Programação Orientada a Objetos (POO) surge justamente para isso, ajudando você a estruturar sistemas maiores sem se perder. Em vez de pensar no programa como uma sequência solta de instruções, você passa a pensar em entidades, responsabilidades e colaboração entre partes.

Em Java, essa forma de pensar é central. Por isso, dominar os primeiros conceitos de POO desde já reduz bastante a dificuldade dos próximos capítulos.

DicaMapa mental do capítulo
  • Ideia central: o que este tema resolve em projetos Java.
  • Linguagem técnica: quais termos você precisa dominar.
  • Aplicação prática: como usar no código do dia a dia.
  • Armadilhas comuns: erros frequentes de iniciantes.
  • Critério de domínio: como saber se você aprendeu de verdade.

Antes de codificar, vale guardar um objetivo simples: ao final do capítulo, você deve olhar para um problema e conseguir responder três perguntas.

  1. Quais são os objetos envolvidos nesse problema?
  2. Quais dados cada objeto precisa guardar?
  3. Quais ações cada objeto precisa realizar?

Se você responder bem essas três perguntas, já começou a pensar como desenvolvedor orientado a objetos.

13.1 O que é Programação Orientada a Objetos

POO é um paradigma de programação que organiza o software em torno de objetos. Um objeto representa algo do domínio do problema, como aluno, curso, pedido, produto, conta bancária ou veículo.

Cada objeto combina:

  • estado: os dados que ele guarda (atributos);
  • comportamento: as ações que ele executa (métodos).

Essa organização facilita manutenção, leitura e evolução do código, principalmente quando o projeto cresce.

13.1.1 Classe x objeto

Uma classe é o molde. Um objeto é a instância criada a partir desse molde.

  • Classe: define quais atributos e métodos existirão.
  • Objeto: é uma ocorrência concreta com valores próprios.

Exemplo mental:

  • Classe: Aluno
  • Objetos: Ana (3o semestre), Bruno (1o semestre), Carla (5o semestre)

Todos são alunos, mas cada objeto guarda seus próprios dados.

13.2 Por que POO ajuda em projetos reais

Em sistemas pequenos, quase qualquer estilo de código parece funcionar. O problema aparece quando o sistema cresce: surgem novas regras, novas telas, novas integrações e novas pessoas no time.

A POO ajuda porque:

  • divide o problema em partes menores e mais claras;
  • melhora reutilização de código;
  • facilita testes e correções;
  • reduz efeitos colaterais quando você altera uma funcionalidade.

Em resumo, POO não é enfeite acadêmico: é estratégia para manter qualidade com o passar do tempo.

13.3 Estudo de caso guiado

Imagine uma pequena plataforma acadêmica para cadastro de alunos, notas e turmas. A cada aula, evoluímos essa plataforma com um novo recurso. Neste capítulo, o foco é aplicar o tema para deixar o sistema mais claro, seguro e fácil de manter.

Vamos começar com uma modelagem mínima:

  • Aluno: nome, semestre, matrícula.
  • Turma: código, disciplina, lista de alunos.
  • Nota: valor, tipo (prova, trabalho), aluno associado.

Perceba que ainda não estamos falando de banco de dados, interface gráfica ou internet. Primeiro, modelamos o problema com boas classes. Essa base é o que permite crescer com segurança depois.

13.4 Construindo a primeira classe com intenção

Ao criar uma classe, pense em responsabilidade única: ela deve representar uma ideia clara do domínio.

No caso da classe Aluno, faz sentido que ela conheça seus próprios dados e consiga se apresentar. Já calcular média da turma inteira pode ser responsabilidade de outra classe, como Turma ou Boletim.

13.5 Exemplo comentado em Java

class Aluno {
  String nome;
  int semestre;

  void apresentar() {
    System.out.println(nome + " - semestre " + semestre);
  }
}

Esse exemplo é simples e útil para iniciar, mas podemos evoluir para uma versão com construtor e método de atualização.

class Aluno {
  String nome;
  int semestre;

  Aluno(String nome, int semestre) {
    this.nome = nome;
    this.semestre = semestre;
  }

  void apresentar() {
    System.out.println(nome + " - semestre " + semestre);
  }

  void avancarSemestre() {
    semestre++;
  }
}

public class Programa {
  public static void main(String[] args) {
    Aluno aluno1 = new Aluno("Ana", 2);
    aluno1.apresentar();

    aluno1.avancarSemestre();
    aluno1.apresentar();
  }
}

Observe três ganhos didáticos aqui:

  1. O construtor garante que o objeto já nasce com dados importantes.
  2. O método concentra comportamento, evitando lógica espalhada.
  3. O código do main fica mais legível, porque expressa intenção.

13.6 Boas práticas para iniciantes em POO

  • Dê nomes que revelem propósito: Aluno, Turma, calcularMedia, aprovarAluno.
  • Evite classes gigantes com responsabilidades misturadas.
  • Prefira métodos curtos e objetivos.
  • Teste pequenos trechos com frequência.
  • Evolua em passos curtos: modelar, codificar, testar, revisar.

13.7 Como identificar uma boa modelagem

Use este mini roteiro sempre que criar classes:

  1. Cada classe representa uma entidade clara do problema?
  2. Os atributos dessa classe fazem sentido para ela?
  3. Os métodos realmente pertencem a essa classe?
  4. O nome da classe e dos métodos está autoexplicativo?
  5. Consigo explicar a estrutura sem ler linha por linha?

Se a maioria das respostas for sim, sua modelagem está no caminho certo.

13.8 Erros clássicos e como evitar

  1. Copiar código sem entender a intenção de cada linha.
  2. Ignorar nomes claros para classes, métodos e variáveis.
  3. Pular testes curtos após cada pequena alteração.
  4. Tentar otimizar antes de ter uma versão correta.
  5. Colocar tudo dentro de uma única classe por medo de separar responsabilidades.
  6. Criar métodos muito longos que fazem várias tarefas ao mesmo tempo.

Quando perceber esses sinais, pare e reorganize antes de continuar. Refatorar cedo custa pouco; refatorar tarde custa caro.

13.9 Microdesafio guiado

Crie uma classe chamada ContaEstudante com os campos nomeTitular e creditos. Em seguida:

  1. Implemente um construtor para inicializar os valores.
  2. Crie um método adicionarCreditos(int valor).
  3. Crie um método usarCreditos(int valor) que só desconta se houver saldo suficiente.
  4. Crie um método exibirResumo() para mostrar o estado atual da conta.

Objetivo pedagógico: praticar encapsulamento mental de dados e comportamento no mesmo objeto.

13.10 Perguntas de revisão rápida

  1. Qual a diferença entre classe e objeto?
  2. Por que métodos melhoram a legibilidade do código?
  3. O que significa responsabilidade única no contexto de classes?
  4. Em qual situação você dividiria uma classe em duas?
  5. Como a POO ajuda quando o projeto começa a crescer?

13.11 Checklist de domínio

13.12 Trilha de prática (20-30 min)

  1. Reescreva o exemplo em um arquivo novo.
  2. Altere duas regras do problema e ajuste o código.
  3. Adicione uma validação extra.
  4. Execute e registre o resultado esperado.
  5. Compare sua solução com a versão anterior e anote o que ficou mais claro.

13.13 Fechamento

Ao finalizar este capítulo, você não deve apenas reconhecer a sintaxe: deve conseguir tomar decisões melhores de implementação. Esse é o passo que diferencia leitura passiva de aprendizado de verdade.

No próximo encontro, continuaremos essa evolução com novas peças da POO e veremos como escrever código mais robusto sem perder simplicidade. O avanço real acontece quando você combina conceito, prática e revisão consciente.

13.14 Expansão técnica complementar

Até aqui, você viu a base conceitual da POO. Agora, vamos adicionar camadas técnicas que costumam aparecer nas primeiras dúvidas de quem começa a programar em Java: referência de objeto, encapsulamento e colaboração entre classes.

13.14.1 Entendendo referência de objeto na prática

Quando você escreve Aluno aluno1 = new Aluno("Ana", 2);, a variável aluno1 não guarda o objeto inteiro. Ela guarda uma referência para a área de memória onde o objeto foi criado. Esse detalhe explica por que duas variáveis podem apontar para o mesmo objeto e por que uma alteração feita por uma referência pode ser observada pela outra.

class Aluno {
  String nome;

  Aluno(String nome) {
    this.nome = nome;
  }
}

public class Programa {
  public static void main(String[] args) {
    Aluno a = new Aluno("Ana");
    Aluno b = a;

    b.nome = "Ana Clara";
    System.out.println(a.nome); // imprime Ana Clara
  }
}

Esse comportamento não é um erro da linguagem. É parte do modelo de objetos. Compreender isso cedo evita bugs difíceis de rastrear quando o sistema crescer.

13.14.2 Encapsulamento desde o início

Em projetos reais, deixar atributos públicos pode gerar estado inválido com facilidade. Por isso, uma boa prática é tornar os atributos privados e controlar mudanças por métodos que validam regras de negócio.

class ContaEstudante {
  private String nomeTitular;
  private int creditos;

  ContaEstudante(String nomeTitular, int creditosIniciais) {
    this.nomeTitular = nomeTitular;
    if (creditosIniciais >= 0) {
      this.creditos = creditosIniciais;
    } else {
      this.creditos = 0;
    }
  }

  void adicionarCreditos(int valor) {
    if (valor > 0) {
      creditos += valor;
    }
  }

  boolean usarCreditos(int valor) {
    if (valor > 0 && valor <= creditos) {
      creditos -= valor;
      return true;
    }
    return false;
  }

  int getCreditos() {
    return creditos;
  }
}

Perceba que o objeto passa a proteger a própria consistência. Isso reduz efeitos colaterais e aumenta confiança na manutenção.

13.14.3 Construtor como ponto de segurança

O construtor não serve apenas para “preencher campos”. Ele também define um estado inicial válido para a classe. Se uma classe exige matrícula obrigatória, por exemplo, o construtor é o lugar correto para exigir esse valor.

Ao pensar assim, você evita objetos parcialmente criados, com dados faltando ou incoerentes. Em outras palavras, o construtor vira uma barreira de qualidade logo no nascimento do objeto.

13.14.4 Coesão: cada classe com uma responsabilidade central

Uma classe coesa concentra operações relacionadas ao mesmo conceito. Se a classe Aluno começa a calcular mensalidade, emitir boleto, enviar e-mail e controlar presença ao mesmo tempo, ela perdeu foco e ficou difícil de evoluir.

Uma regra prática útil para iniciantes é: se você descreve a classe e precisa usar “e” muitas vezes, talvez ela esteja assumindo responsabilidades demais.

13.14.5 Colaboração entre objetos (composição)

Na POO, objetos raramente vivem isolados. Eles colaboram. Uma Turma pode ter um objeto Professor e vários objetos Aluno. Esse tipo de relação é chamado de composição e ajuda a representar o domínio de forma natural.

class Professor {
  String nome;

  Professor(String nome) {
    this.nome = nome;
  }
}

class Turma {
  String codigo;
  Professor responsavel;

  Turma(String codigo, Professor responsavel) {
    this.codigo = codigo;
    this.responsavel = responsavel;
  }

  void exibirResumo() {
    System.out.println("Turma " + codigo + " - Professor: " + responsavel.nome);
  }
}

Modelar essas relações cedo melhora sua leitura de sistemas maiores e prepara o terreno para temas como herança e polimorfismo nos capítulos seguintes.

13.14.6 Critérios técnicos para revisar seu próprio código

Ao finalizar um exercício de POO, faça uma revisão rápida com estas perguntas:

  1. Existe algum atributo que pode receber valores inválidos sem validação?
  2. Algum método está assumindo tarefas que pertencem a outra classe?
  3. O construtor garante estado inicial consistente?
  4. Os nomes das classes e métodos comunicam intenção sem ambiguidade?
  5. Se outro colega ler seu código, ele entende o fluxo sem explicação oral?

Esse tipo de autoavaliação é um hábito simples que acelera sua evolução técnica de forma consistente.

NotaExpansão didática complementar

Com esse aprofundamento, você já consegue enxergar a POO não apenas como teoria, mas como ferramenta concreta para produzir código robusto, legível e preparado para mudança. A partir daqui, cada novo conteúdo da trilha ficará mais claro porque você já estabeleceu uma base sólida de modelagem, responsabilidade e qualidade estrutural.