POO — Módulo 1 · Fundamentos de Orientação a Objetos
Unidade 1 · Introdução ao Paradigma OO
A Programação Orientada a Objetos (POO) organiza o código em torno de objetos que combinam dados (atributos) e comportamentos (métodos). É o paradigma dominante no desenvolvimento de software moderno.
Paradigma Procedural
Foco em funções e procedimentos. Dados e funções separados. Difícil de escalar e manter. Ex: C, Pascal.
Paradigma OO
Foco em objetos. Dados + comportamento juntos. Modela o mundo real. Reutilizável. Ex: Java, Python, C++.
Os 4 Pilares da POO
Pilar
O que é
Exemplo
Encapsulamento
Esconder dados internos, expor só o necessário
Atributos private + getters/setters
Herança
Uma classe reutiliza atributos/métodos de outra
Cachorro extends Animal
Polimorfismo
O mesmo método se comporta diferente por tipo
animal.falar() → "Au" ou "Miau"
Abstração
Modelar só o que é relevante ao problema
Classe Conta sem detalhe bancário interno
Unidade 2 · Introdução ao Java
Java é fortemente tipada, compilada e orientada a objetos. O código é compilado para bytecode que roda na JVM (Java Virtual Machine) — "escreva uma vez, rode em qualquer lugar".
// Tipos primitivos principais
int idade = 20;
double salario = 3500.50;
boolean ativo = true;
char letra = 'A';
String nome = "Ana"; // String é objeto, não primitivo
// Operadores
int soma = 10 + 5; // 15
int resto = 10 % 3; // 1 (módulo)
boolean ok = (5 > 3); // true
⚠ Importante
Java é case-sensitive: "nome" e "Nome" são variáveis diferentes. Todo programa Java precisa de um método public static void main(String[] args) como ponto de entrada.
Unidade 3 · Classes e Objetos
A classe é o molde/template. O objeto é a instância concreta criada a partir da classe com a palavra-chave new.
// Definindo a classe
public class Carro {
String marca; // atributo
int ano;
// Construtor
public Carro(String marca, int ano) {
this.marca = marca;
this.ano = ano;
}
// Método
public void buzinar() {
System.out.println(marca + ": Biiiip!");
}
}
// Criando objetos (instâncias)
Carro c1 = new Carro("Toyota", 2022);
Carro c2 = new Carro("Honda", 2023);
c1.buzinar(); // Toyota: Biiiip!
⚠ Importante
this referencia o próprio objeto. Usado para distinguir atributos de parâmetros de mesmo nome. new aloca memória e chama o construtor.
Unidade 4 · Programando em Java — Controle de Fluxo
// if-else
if (idade >= 18) {
System.out.println("Maior de idade");
} else {
System.out.println("Menor de idade");
}
// for
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
// while
while (saldo > 0) {
saldo -= 100;
}
// switch
switch (dia) {
case 1: System.out.println("Seg"); break;
case 2: System.out.println("Ter"); break;
default: System.out.println("Outro");
}
Exercícios Resolvidos
Exercício 1: Qual a diferença entre classe e objeto?
→ Classe é o molde. Objeto é a instância concreta.
Ex: Carro é a classe (define marca, ano, buzinar). Toyota 2022 é um objeto específico dessa classe. Podem existir vários objetos da mesma classe.
Exercício 2: O que faz a palavra-chave this em Java?
→ Referencia o objeto atual — distingue atributos de parâmetros com mesmo nome.
Em public Carro(String marca) { this.marca = marca; } — this.marca é o atributo, marca é o parâmetro.
POO — Módulo 2 · Aprofundando na Orientação a Objetos
Unidade 1 · Vetores (Arrays)
Um array é uma coleção de elementos do mesmo tipo com tamanho fixo. Índice começa em 0.
// Declarar e inicializar
int[] notas = new int[5]; // array de 5 inteiros (default 0)
String[] nomes = {"Ana","Bia","Carlos"}; // inicialização direta
// Acessar e modificar
notas[0] = 8;
notas[1] = 9;
System.out.println(notas.length); // 5 (tamanho)
// Percorrer com for-each
for (String n : nomes) {
System.out.println(n);
}
// Array 2D (matriz)
int[][] matriz = new int[3][3];
matriz[0][0] = 1;
matriz[1][1] = 5;
⚠ Importante
Array em Java tem tamanho fixo — não pode crescer após criado. Para coleções dinâmicas, use ArrayList. Acessar índice fora do limite lança ArrayIndexOutOfBoundsException.
Unidade 2 · Métodos, Classes e Objetos — Visão Aprofundada
public class ContaBancaria {
private double saldo; // encapsulado
private static int totalContas; // compartilhado por todas as instâncias
// Construtor
public ContaBancaria(double saldoInicial) {
this.saldo = saldoInicial;
totalContas++;
}
// Método de instância
public void depositar(double valor) {
if (valor > 0) saldo += valor;
}
// Método estático
public static int getTotalContas() {
return totalContas;
}
// Sobrecarga de método (overloading)
public void sacar(double valor) { saldo -= valor; }
public void sacar(double valor, String motivo) {
saldo -= valor;
System.out.println("Saque: " + motivo);
}
}
Modificador
Acesso
public
Qualquer classe em qualquer pacote
protected
Mesma classe, mesmo pacote ou subclasses
default (sem mod.)
Só mesmo pacote
private
Só a própria classe
⚠ static vs instância
static: pertence à classe — compartilhado por todos os objetos. Instância: cada objeto tem o seu. Static é acessado via NomeClasse.metodo(), não precisa de objeto.
Unidade 3 · Coleta de Lixo e Pacotes
O Garbage Collector (GC) da JVM libera automaticamente memória de objetos sem referências. Em Java, não existe delete manual como em C++.
// Pacotes organizam classes
package br.edu.ufms.poo; // declara o pacote
import java.util.ArrayList; // importa classe de outro pacote
import java.util.*; // importa tudo do pacote java.util
// Objeto sem referência → elegível para GC
Carro c = new Carro("Toyota", 2022);
c = null; // GC pode coletar o objeto anterior
Exercícios Resolvidos
Exercício 3: Qual a diferença entre método static e método de instância?
→ Static pertence à classe (acessado sem criar objeto). Instância pertence ao objeto (precisa de new).
ContaBancaria.getTotalContas() — static, não precisa de objeto. minhaConta.depositar(100) — instância, precisa do objeto minhaConta.
Exercício 4: O que é sobrecarga (overloading) de método?
→ Mesmo nome de método com parâmetros diferentes (tipo ou quantidade).
sacar(100.0) e sacar(100.0, "Aluguel") são sobrecargas — mesmo nome, assinaturas diferentes. O Java escolhe qual chamar pelo tipo/quantidade dos argumentos.
POO — Módulo 3 · Pilares da POO
Unidade 1 · Herança e Polimorfismo
Herança: uma classe filha (subclasse) herda atributos e métodos da classe pai (superclasse). Usa extends. Evita duplicação de código.
// Superclasse
public class Animal {
protected String nome;
public Animal(String nome) { this.nome = nome; }
public void falar() {
System.out.println(nome + " faz algum som");
}
}
// Subclasse — herda de Animal
public class Cachorro extends Animal {
public Cachorro(String nome) {
super(nome); // chama construtor do pai
}
@Override // sobrescreve o método do pai
public void falar() {
System.out.println(nome + ": Au Au!");
}
}
public class Gato extends Animal {
public Gato(String nome) { super(nome); }
@Override
public void falar() { System.out.println(nome + ": Miau!"); }
}
// Polimorfismo em ação
Animal[] animais = { new Cachorro("Rex"), new Gato("Mimi") };
for (Animal a : animais) {
a.falar(); // cada um chama seu próprio falar()
}
⚠ Importante
@Override é anotação que indica sobrescrita — o compilador verifica se o método realmente existe no pai. super acessa membros da superclasse. Java só permite herança simples (uma única superclasse).
Unidade 2 · Encapsulamento e Modificadores de Acesso
public class Pessoa {
private String nome; // só acessível dentro desta classe
private int idade;
// Getter — leitura controlada
public String getNome() { return nome; }
// Setter — escrita com validação
public void setIdade(int idade) {
if (idade >= 0 && idade <= 150) {
this.idade = idade;
}
}
}
⚠ Encapsulamento
Atributos private + acesso via getters/setters. O setter pode validar antes de aceitar o valor — protege o estado interno do objeto de valores inválidos.
Unidade 3 · Interfaces e Abstração
// Classe abstrata — não pode ser instanciada diretamente
public abstract class Forma {
public abstract double calcularArea(); // sem implementação
public void exibir() { // pode ter implementação
System.out.println("Área: " + calcularArea());
}
}
// Interface — contrato puro
public interface Desenhavel {
void desenhar(); // implicitamente public abstract
default void apagar() { // método default (Java 8+)
System.out.println("Apagando...");
}
}
// Implementação
public class Circulo extends Forma implements Desenhavel {
private double raio;
public Circulo(double raio) { this.raio = raio; }
@Override public double calcularArea() { return Math.PI * raio * raio; }
@Override public void desenhar() { System.out.println("Desenhando circulo"); }
}
Classe Abstrata
Interface
Instanciar
Não
Não
Herança/Implement.
extends (1 só)
implements (várias!)
Atributos
Qualquer tipo
Só constantes (static final)
Métodos concretos
Sim
Só default/static (Java 8+)
Uso
Compartilhar código base
Definir contrato/comportamento
Unidade 4 · Classes e Métodos Genéricos
// Classe genérica — funciona com qualquer tipo T
public class Caixa<T> {
private T conteudo;
public void guardar(T item) { this.conteudo = item; }
public T pegar() { return conteudo; }
}
// Uso
Caixa<String> cx1 = new Caixa<>();
cx1.guardar("Olá");
Caixa<Integer> cx2 = new Caixa<>();
cx2.guardar(42);
// Método genérico
public static <T extends Comparable<T>> T maior(T a, T b) {
return a.compareTo(b) >= 0 ? a : b;
}
Exercícios Resolvidos
Exercício 5: Qual a diferença entre sobrescrita (override) e sobrecarga (overload)?
→ Override: redefine método do pai na subclasse (mesmo nome e assinatura). Overload: mesmo nome, assinaturas diferentes na mesma classe.
Override = polimorfismo em tempo de execução. Overload = polimorfismo em tempo de compilação.
Exercício 6: Uma classe pode implementar mais de uma interface?
→ Sim — Java permite implements múltiplos: class X implements A, B, C.
Isso resolve a limitação da herança simples. Uma classe pode ter um único pai (extends) mas múltiplos contratos (implements).
POO — Módulo 4 · Conceitos Avançados
Unidade 1 · Coleções (Collections)
O Java Collections Framework fornece estruturas de dados dinâmicas prontas. As principais estão no pacote java.util.
import java.util.*;
// ArrayList — lista dinâmica ordenada, permite duplicatas
List<String> lista = new ArrayList<>();
lista.add("Ana");
lista.add("Bia");
lista.add("Ana"); // duplicata permitida
lista.remove("Bia");
lista.get(0); // "Ana"
lista.size(); // 2
// Percorrer
for (String s : lista) System.out.println(s);
// LinkedList — eficiente para inserções/remoções no meio
List<Integer> ll = new LinkedList<>();
ll.add(1); ll.add(2); ll.add(3);
Unidade 2 · Conjuntos (Set) e Mapas (Map)
// HashSet — não permite duplicatas, sem ordem garantida
Set<String> set = new HashSet<>();
set.add("A"); set.add("B"); set.add("A"); // ignora 2º "A"
set.size(); // 2
// TreeSet — sem duplicatas, mantém ordem crescente
Set<Integer> ts = new TreeSet<>();
ts.add(30); ts.add(10); ts.add(20);
// ts = [10, 20, 30] — sempre ordenado
// HashMap — pares chave-valor, sem ordem
Map<String, Integer> mapa = new HashMap<>();
mapa.put("Ana", 25);
mapa.put("Bia", 30);
mapa.get("Ana"); // 25
mapa.containsKey("Bia"); // true
// Percorrer mapa
for (Map.Entry<String, Integer> e : mapa.entrySet()) {
System.out.println(e.getKey() + " = " + e.getValue());
}
Coleção
Duplicatas
Ordem
Acesso
Uso
ArrayList
Sim
Inserção
O(1) por índice
Lista geral
LinkedList
Sim
Inserção
O(n)
Fila/Deque
HashSet
Não
Nenhuma
O(1)
Unicidade
TreeSet
Não
Crescente
O(log n)
Conjunto ordenado
HashMap
Chave única
Nenhuma
O(1)
Dicionário
Unidade 3 · Tratamento de Exceções
// try-catch-finally
try {
int resultado = 10 / 0; // lança ArithmeticException
String s = null;
s.length(); // lança NullPointerException
} catch (ArithmeticException e) {
System.out.println("Erro aritmético: " + e.getMessage());
} catch (NullPointerException e) {
System.out.println("Referência nula!");
} finally {
System.out.println("Sempre executado!"); // limpar recursos
}
// Criar exceção personalizada
public class SaldoInsuficienteException extends RuntimeException {
public SaldoInsuficienteException(double valor) {
super("Saldo insuficiente para sacar: R$" + valor);
}
}
// Lançar exceção
public void sacar(double valor) {
if (valor > saldo) throw new SaldoInsuficienteException(valor);
saldo -= valor;
}
Tipo
Exemplo
Obrigado tratar?
Checked Exception
IOException, SQLException
Sim — try-catch ou throws
Unchecked (Runtime)
NullPointerException, ArrayIndexOutOfBounds
Não obrigatório
Error
OutOfMemoryError, StackOverflowError
Não trate — grave!
Unidade 4 · Trabalhando com Arquivos e Fluxos
import java.io.*;
import java.nio.file.*;
// Escrever em arquivo
try (BufferedWriter bw = new BufferedWriter(new FileWriter("dados.txt"))) {
bw.write("Linha 1\n");
bw.write("Linha 2\n");
} // fecha automaticamente (try-with-resources)
// Ler arquivo linha por linha
try (BufferedReader br = new BufferedReader(new FileReader("dados.txt"))) {
String linha;
while ((linha = br.readLine()) != null) {
System.out.println(linha);
}
}
// NIO (moderno — Java 7+)
Path path = Paths.get("dados.txt");
List<String> linhas = Files.readAllLines(path);
Files.write(path, linhas);
⚠ try-with-resources
O bloco try (recurso) fecha automaticamente o recurso ao terminar, mesmo se lançar exceção. Evita vazamento de recursos — sempre prefira para streams e arquivos.
Exercícios Resolvidos
Exercício 7: Quando usar HashSet em vez de ArrayList?
→ Quando precisar garantir unicidade e não importar a ordem.
HashSet rejeita duplicatas automaticamente e busca em O(1). ArrayList permite duplicatas e busca linear O(n). Para CPFs únicos de usuários, por exemplo, HashSet é melhor.
Exercício 8: O que é o bloco finally?
→ Código executado sempre, independente de exceção ou não.
Usado para liberar recursos (fechar arquivos, conexões). Com try-with-resources, o finally explícito ficou menos necessário — o fechamento é automático.
APOO — Módulo 1 · Introdução à Orientação a Objetos
Unidade 1 · Revisão dos Modelos de Processos de Software
Um processo de desenvolvimento de software define as etapas para criar um sistema: análise, projeto, implementação, teste e manutenção. O modelo escolhido impacta custo, prazo e qualidade.
Modelo
Característica
Vantagem
Desvantagem
Cascata
Fases sequenciais, sem volta
Simples, documentado
Inflexível a mudanças
Incremental
Entrega parcial em ciclos
Feedback cedo
Pode acumular dívida técnica
Espiral
Baseado em riscos
Gerencia riscos
Complexo, caro
Ágil (Scrum/XP)
Iterativo, colaborativo
Adaptável, rápido
Difícil de escalar
Prototipagem
Protótipo rápido para validar
Requisitos ficam claros
Protótipo pode virar produto mal feito
⚠ Importante
A escolha do modelo depende do projeto: requisitos estáveis → Cascata. Requisitos mudam → Ágil. Alto risco → Espiral. O modelo OO se encaixa melhor com processos iterativos e incrementais.
Unidade 2 · Conceitos de Orientação a Objetos
Objeto
Entidade com estado (atributos) e comportamento (métodos). Ex: objeto Carro tem cor, velocidade e pode acelerar().
Classe
Descrição/template de um conjunto de objetos com mesmas características. "Planta baixa" do objeto.
Mensagem
Objetos se comunicam enviando mensagens (chamando métodos). Ex: carro.acelerar(50) é uma mensagem.
Responsabilidade
O que um objeto sabe (atributos) e o que ele faz (métodos). Cada objeto tem responsabilidade bem definida.
Exemplo — Modelagem OO
Sistema de biblioteca: objetos Livro (titulo, isbn, estaDisponivel()), Leitor (nome, cpf, pegarEmprestado()), Emprestimo (livro, leitor, dataDevolver()).
Exercícios Resolvidos
Exercício 9: Por que o modelo ágil é mais adequado para a maioria dos projetos OO modernos?
→ POO facilita refatoração e mudanças — encaixa com o ciclo iterativo do ágil.
Encapsulamento e herança permitem mudar partes do sistema sem quebrar outras. No cascata, mudanças são custosas. No ágil + POO, cada iteração entrega novas classes/funcionalidades sem reescrever tudo.
APOO — Módulo 2 · Análise Orientada a Objetos
Unidade 1 · Processos de Análise OO
A análise OO identifica os objetos do mundo real relevantes ao sistema, seus atributos e relacionamentos. O resultado é um modelo de domínio independente de tecnologia.
Passos: (1) Identificar classes candidatas nos requisitos. (2) Filtrar classes relevantes. (3) Definir atributos e operações. (4) Identificar relacionamentos. (5) Verificar com o cliente.
Cartões físicos para cada classe listando: nome da classe, responsabilidades (o que faz/sabe) e colaboradores (quem usa). Técnica simples e eficaz para análise em equipe.
⚠ Importante
Na análise, foque no O QUE o sistema deve fazer, não no COMO. Evite decisões de implementação (linguagem, banco, framework) nessa fase.
Unidade 2 · UML — Linguagem de Modelagem Unificada
A UML (Unified Modeling Language) é a linguagem padrão para modelar sistemas OO. Não é uma metodologia — é uma notação visual.
Diagrama UML
Tipo
O que modela
Diagrama de Classes
Estrutural
Classes, atributos, métodos e relacionamentos
Diagrama de Objetos
Estrutural
Instâncias concretas em momento específico
Diagrama de Casos de Uso
Comportamental
Atores e funcionalidades do sistema
Diagrama de Sequência
Comportamental
Troca de mensagens entre objetos no tempo
Diagrama de Atividades
Comportamental
Fluxo de trabalho/algoritmo
Diagrama de Estados
Comportamental
Ciclo de vida de um objeto
Diagrama de Classes — Notação
┌──────────────────────┐
│ Conta │ ← Nome da classe
├──────────────────────┤
│ - numero: String │ ← Atributos (- private, + public, # protected)
│ - saldo: double │
│ # titular: String │
├──────────────────────┤
│ + depositar(v:double) │ ← Métodos
│ + sacar(v:double) │
│ + getSaldo(): double │
└──────────────────────┘
Relacionamentos:
────────────── Associação (usa)
──────────────◁ Herança/Generalização (extends)
- - - - - - -◁ Realização (implements interface)
◆──────────── Composição (parte não existe sem o todo)
◇──────────── Agregação (parte pode existir sem o todo)
⚠ Composição vs Agregação
Composição: Pedido ◆── ItemPedido. Se o Pedido for deletado, os itens também são. Agregação: Turma ◇── Aluno. Se a Turma acabar, o Aluno ainda existe.
Exercícios Resolvidos
Exercício 10: Qual diagrama UML mostra a ordem das mensagens trocadas entre objetos?
→ Diagrama de Sequência — eixo vertical = tempo, barras = objetos, setas = mensagens.
Ex: Usuario → Sistema: login(senha) → BD: verificar(usuario, senha) → BD → Sistema: ok → Sistema → Usuario: tela principal.
Exercício 11: Qual a diferença entre composição e agregação no diagrama de classes?
→ Composição: parte não existe sem o todo (losango cheio). Agregação: parte existe independentemente (losango vazio).
Página não existe sem Livro (composição). Aluno existe sem Turma (agregação).
APOO — Módulo 3 · Projeto Orientado a Objetos
Unidade 1 · Desenho de Projeto OO
O projeto OO transforma o modelo de análise em uma solução técnica. Define como as classes serão implementadas, os padrões usados e a arquitetura do sistema.
Princípios SOLID
Single Responsibility — 1 classe = 1 responsabilidade Open/Closed — aberto para extensão, fechado para modificação Liskov — subclasse substituível pela superclasse Interface Segregation — interfaces coesas e pequenas Dependency Inversion — dependa de abstrações
Coesão e Acoplamento
Alta coesão: classe tem responsabilidade única e bem definida. Bom! Baixo acoplamento: classes pouco dependentes entre si. Bom! Objetivo: maximizar coesão e minimizar acoplamento.
Exemplo — Violação do SRP
Classe RelatorioVendas que busca dados do BD, formata e imprime. Três responsabilidades! Deveria ser: BuscadorVendas + FormataRelatorio + ImpressoraRelatorio.
Exemplo — Open/Closed
Sistema de pagamento: em vez de if (tipo == "pix") ... else if (tipo == "cartao") ..., criar interface Pagamento com pagar(), e cada tipo implementa. Adicionar novo tipo = nova classe, sem mexer no código existente.
Unidade 2 · Padrões GRASP
GRASP (General Responsibility Assignment Software Patterns) são 9 princípios para atribuir responsabilidades a classes e objetos no projeto OO.
Padrão GRASP
Pergunta que responde
Solução
Especialista (Expert)
Quem tem responsabilidade por algo?
A classe que tem a informação necessária
Criador (Creator)
Quem deve criar instâncias de X?
Quem contém, agrega ou usa X
Controlador (Controller)
Quem recebe eventos do sistema?
Classe controladora (não UI) coordena casos de uso
Baixo Acoplamento
Como reduzir dependências?
Atribuir responsabilidade que minimiza ligações
Alta Coesão
Como manter objetos compreensíveis?
Responsabilidades relacionadas na mesma classe
Polimorfismo
Como tratar alternativas por tipo?
Usar polimorfismo em vez de if/switch por tipo
Indireção
Como evitar acoplamento direto?
Introduzir objeto intermediário
Fabricação Pura
Quem cuida de responsabilidades de infra?
Classe artificial (DAO, Repository) sem domínio
Variações Protegidas
Como proteger de mudanças externas?
Interface estável envolve o que varia
Exemplo — Especialista (Expert)
Quem calcula o total do pedido? A classe Pedido — ela tem os itens e preços. Não é a classe Cliente nem a Tela que deve fazer esse cálculo.
Exemplo — Criador (Creator)
Quem cria ItemPedido? A classe Pedido — ela contém/agrega os itens. Logo, Pedido é responsável por criar e gerenciar seus itens.
Exemplo — Fabricação Pura
PedidoDAO (Data Access Object) — classe artificial que cuida de salvar/buscar Pedidos no banco. Não representa nada do domínio, mas evita que Pedido saiba de SQL.
Exercícios Resolvidos
Exercício 12: Pelo padrão Expert, quem deve calcular o subtotal de um ItemPedido?
→ A classe ItemPedido — ela tem preço e quantidade.
Expert: quem tem a informação necessária tem a responsabilidade. ItemPedido tem preco e qtd → calcula subtotal = preco * qtd.
Exercício 13: O que é um DAO e qual padrão GRASP ele representa?
→ DAO é classe artificial para acesso a dados — representa Fabricação Pura.
Sem DAO, a classe de domínio (Pedido) precisaria saber de SQL — alto acoplamento com infra. DAO isola essa responsabilidade.
APOO — Módulo 4 · Prática da Análise e Projeto
Unidade 1 · Ferramentas e Proposta de Projeto
Ferramentas UML populares: Astah (comercial, muito usada em acadêmicos), draw.io (gratuito, web), StarUML, PlantUML (diagramas via texto), Lucidchart (colaborativo).
Processo Completo de Análise e Projeto OO
Fase
Entregável
Ferramenta/Técnica
Levantamento de Requisitos
Casos de uso, histórias de usuário
Entrevistas, diagrama de casos de uso
Análise OO
Modelo de domínio, diagrama de classes (conceitual)
CRC Cards, UML classes
Projeto OO
Diagrama de classes detalhado, sequência, GRASP
Astah, draw.io, SOLID + GRASP
Implementação
Código-fonte
Java, IDE (Eclipse/IntelliJ)
Testes
Casos de teste, relatório
JUnit, testes de integração
Unidade 2 · Implementação OO
Boas práticas de implementação OO: seguir SOLID, aplicar GRASP, usar padrões de projeto (Design Patterns) quando apropriado, e garantir que o código reflita o modelo de domínio.
// Exemplo completo: do modelo ao código
// Análise: Sistema de Pedidos
// Classes: Pedido, ItemPedido, Produto, Cliente
public class Produto {
private String nome;
private double preco;
public Produto(String nome, double preco) {
this.nome = nome; this.preco = preco;
}
public double getPreco() { return preco; }
public String getNome() { return nome; }
}
public class ItemPedido {
private Produto produto;
private int quantidade;
public ItemPedido(Produto produto, int qtd) {
this.produto = produto; this.quantidade = qtd;
}
// Expert: ItemPedido calcula seu próprio subtotal
public double getSubtotal() {
return produto.getPreco() * quantidade;
}
}
public class Pedido {
private List<ItemPedido> itens = new ArrayList<>();
private Cliente cliente;
// Creator: Pedido cria seus ItemPedidos
public void adicionarItem(Produto p, int qtd) {
itens.add(new ItemPedido(p, qtd));
}
// Expert: Pedido calcula o total (soma dos subtotais)
public double getTotal() {
return itens.stream()
.mapToDouble(ItemPedido::getSubtotal)
.sum();
}
}
Exercícios Resolvidos
Exercício 14: No exemplo acima, qual padrão GRASP justifica Pedido::adicionarItem criar ItemPedidos?
Regra do Creator: B cria A se B contém A, B agrega A, B usa A ou B tem dados para inicializar A. Pedido agrega ItemPedidos → Pedido cria ItemPedidos.
Exercício 15: Por que usar stream().mapToDouble().sum() em vez de um for loop para calcular o total?
→ Mais expressivo, conciso e funcional — o código comunica a intenção claramente.
Streams Java facilitam operações em coleções. mapToDouble converte cada item para double, sum() soma tudo. O resultado é o mesmo do for, mas mais legível e menos propenso a erros.
📝 Cola de Prova — POO & APOO
Os 4 Pilares da POO
Pilar
Palavra-chave Java
Resumo
Encapsulamento
private + get/set
Esconde estado interno, controla acesso
Herança
extends, super
Reutiliza código do pai. Java: herança simples
Polimorfismo
@Override
Mesmo método, comportamento diferente por tipo
Abstração
abstract, interface
Esconde complexidade, expõe o essencial
Classe Abstrata vs Interface
Classe Abstrata
Interface
Herança
extends (1 só)
implements (várias)
Atributos
Qualquer
Só static final
Métodos concretos
Sim
default/static (Java 8+)
Uso
Compartilhar código
Definir contrato
Coleções — Escolha Rápida
Precisa de...
Use
Lista com duplicatas e acesso por índice
ArrayList
Inserção/remoção frequente no meio
LinkedList
Elementos únicos, sem ordem
HashSet
Elementos únicos, ordenados
TreeSet
Busca por chave (dicionário)
HashMap
Dicionário em ordem crescente de chave
TreeMap
GRASP — Resumo dos 9 Padrões
Padrão
Ideia central
Expert
Responsabilidade vai para quem tem a informação
Creator
Cria quem contém/agrega/usa
Controller
Classe coordenadora recebe eventos do sistema
Baixo Acoplamento
Minimizar dependências entre classes
Alta Coesão
Classe com responsabilidade única e bem definida
Polimorfismo
Usar polimorfismo em vez de if/switch por tipo
Indireção
Intermediário evita acoplamento direto
Fabricação Pura
Classe artificial para responsabilidade de infra (ex: DAO)