Médio Java
Sistema de pagamentos com instanceof pattern
Enunciado
Crie uma hierarquia de pagamentos: Pagamento (abstrata) com método processar(). As subclasses CartaoCredito e Boleto devem implementar processar() imprimindo mensagens específicas. Além disso, CartaoCredito tem um método autorizar() e Boleto tem um método gerarCodigoBarras(). No main, crie uma lista de Pagamento com um cartão e um boleto. Percorra a lista, chame processar() e, usando instanceof com pattern, chame o método específico de cada tipo.
Requisitos
Pagamentoé uma classe abstrata com método abstratoprocessar().CartaoCredito.processar()imprime "Processando pagamento com cartão de crédito." eautorizar()imprime "Autorizando cartão...".Boleto.processar()imprime "Processando pagamento com boleto." egerarCodigoBarras()imprime "Gerando código de barras...".- No
main, useinstanceofcom pattern para chamar os métodos específicos sem casting explícito.
Código inicial
import java.util.List;
import java.util.ArrayList;
abstract class Pagamento {
abstract void processar();
}
// TODO: crie CartaoCredito e Boleto
public class Main {
public static void main(String[] args) {
List<Pagamento> pagamentos = new ArrayList<>();
// TODO: adicione um CartaoCredito e um Boleto
// TODO: percorra e processe, usando instanceof pattern
}
}
Saída esperada
Processando pagamento com cartão de crédito.
Autorizando cartão...
Processando pagamento com boleto.
Gerando código de barras...
Ver dica
Use if (p instanceof CartaoCredito c) { c.autorizar(); } para testar e converter em uma única linha.
Mostrar solução
import java.util.List;
import java.util.ArrayList;
abstract class Pagamento {
abstract void processar();
}
class CartaoCredito extends Pagamento {
@Override
void processar() {
System.out.println("Processando pagamento com cartão de crédito.");
}
void autorizar() {
System.out.println("Autorizando cartão...");
}
}
class Boleto extends Pagamento {
@Override
void processar() {
System.out.println("Processando pagamento com boleto.");
}
void gerarCodigoBarras() {
System.out.println("Gerando código de barras...");
}
}
public class Main {
public static void main(String[] args) {
List<Pagamento> pagamentos = new ArrayList<>();
pagamentos.add(new CartaoCredito());
pagamentos.add(new Boleto());
for (Pagamento p : pagamentos) {
p.processar(); // despacho dinâmico
// instanceof com pattern: declara variável já convertida
if (p instanceof CartaoCredito c) {
c.autorizar();
} else if (p instanceof Boleto b) {
b.gerarCodigoBarras();
}
}
}
}
Passo a passo
- Definimos
Pagamentocomo classe abstrata com o métodoprocessar(). Isso força as subclasses a implementarem o comportamento. CartaoCreditoestendePagamentoe implementaprocessar()com a mensagem específica. Também adiciona o métodoautorizar().Boletofaz o mesmo, comprocessar()egerarCodigoBarras().- No
main, criamos uma lista dePagamentoe adicionamos instâncias deCartaoCreditoeBoleto. Isso é polimorfismo: a lista aceita qualquer subtipo. - Iteramos com
for-each. A chamadap.processar()é resolvida dinamicamente: para o cartão, executa a versão deCartaoCredito; para o boleto, a deBoleto. - Usamos
p instanceof CartaoCredito cpara verificar se o objeto é um cartão e, em caso afirmativo, a variávelcjá está tipada comoCartaoCredito, permitindo chamarc.autorizar()sem cast explícito. - O
else iffaz o mesmo paraBoleto, chamandob.gerarCodigoBarras(). - A saída segue a ordem de inserção na lista.
Por que funciona
O polimorfismo permite que a lista de Pagamento armazene diferentes tipos. O método processar() é sobrescrito e chamado dinamicamente. O instanceof com pattern é um recurso moderno que simplifica a verificação de tipo e o casting, tornando o código mais limpo e seguro. Sem ele, precisaríamos de um cast explícito após a verificação.
Erros comuns
- Esquecer o
else if: se usar doisifseparados, ambos podem ser verdadeiros? Não, mas se um objeto for de um tipo, o outroifserá falso. No entanto, usarelse ifdeixa a intenção clara e evita verificações desnecessárias. - Ordem dos
instanceof: seCartaoCreditofosse subclasse deBoleto(não é o caso), a ordem importaria. Aqui, como são irmãos, não há problema. - Não usar pattern:
if (p instanceof CartaoCredito) { ((CartaoCredito) p).autorizar(); }funciona, mas é mais verboso e propenso a erros.
Outra forma de resolver
Poderia-se usar o método getClass().getSimpleName() para decidir, mas isso não é polimórfico e quebra o princípio de aberto/fechado. A forma com instanceof pattern é preferível.
Saída esperada
Processando pagamento com cartão de crédito.
Autorizando cartão...
Processando pagamento com boleto.
Gerando código de barras...