14  Interfaces e polimorfismo

Adicionar comandos sem alterar o processador

14.1 Objetivos de aprendizagem

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

  • definir um contrato com interface;
  • implementar o mesmo contrato em classes diferentes;
  • usar referências do tipo da interface;
  • explicar despacho dinâmico;
  • adicionar comportamento sem editar uma cadeia de condicionais.

14.2 Contrato de comando

A interface Comando é implementada por ComandoOi, ComandoAjuda e ComandoDica; o processador depende apenas da interface.

Implementações diferentes atendem ao mesmo contrato.

Uma interface descreve o que um objeto oferece sem impor uma hierarquia de estado:

interface Comando {
    String nome();
    String executar();
}

Diferentes classes podem implementar o contrato:

final class ComandoAjuda implements Comando {
    @Override
    public String nome() {
        return "ajuda";
    }

    @Override
    public String executar() {
        return "Comandos: ajuda e dica.";
    }
}

final class ComandoDica implements Comando {
    @Override
    public String nome() {
        return "dica";
    }

    @Override
    public String executar() {
        return "Programe contra contratos pequenos.";
    }
}

14.3 Polimorfismo em execução

import java.util.List;

interface Comando {
    String nome();
    String executar();
}

final class ComandoAjuda implements Comando {
    public String nome() {
        return "ajuda";
    }

    public String executar() {
        return "Comandos: ajuda e dica.";
    }
}

final class ComandoDica implements Comando {
    public String nome() {
        return "dica";
    }

    public String executar() {
        return "Programe contra contratos pequenos.";
    }
}

public class Capitulo13Polimorfismo {
    static String processar(String entrada, List<Comando> comandos) {
        for (Comando comando : comandos) {
            if (comando.nome().equalsIgnoreCase(entrada)) {
                return comando.executar();
            }
        }
        return "Comando desconhecido.";
    }

    public static void main(String[] args) {
        List<Comando> comandos =
                List.of(new ComandoAjuda(), new ComandoDica());

        System.out.println(processar("dica", comandos));
    }
}

A lista armazena objetos diferentes por meio do mesmo contrato. Quando executar() é chamado, a JVM seleciona a implementação do objeto concreto. Isso é despacho dinâmico.

14.4 Interface ou classe abstrata?

Prefira interface quando o foco é um papel que classes diferentes podem desempenhar. Use classe abstrata quando as subclasses realmente compartilham estado e implementação.

Uma classe pode implementar várias interfaces, mas só pode estender uma classe.

14.5 Evolução do projeto: versão 13

Cada comando passa a ser um objeto. Para adicionar ComandoSobre, crie uma classe e registre uma instância; a lógica central de processamento permanece inalterada.

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

14.6 Prática verificável

  1. Implemente ComandoSobre.
  2. Adicione-o à lista.
  3. Confirme que processar não foi alterado.
  4. Crie uma implementação de teste que sempre devolva "OK".

Casos de teste:

Entrada Implementação chamada
ajuda ComandoAjuda
DICA ComandoDica
xyz nenhuma; resposta padrão
DicaSinal de polimorfismo útil

O código consumidor conhece o contrato Comando, não uma sequência de verificações para cada classe concreta.