Polimorfismo, originário do grego, significa "muitas formas" (poli = muitas, morphos = formas). Ele permite que referências de tipos de classes mais abstratas representem o comportamento das classes concretas que referenciam. Assim, um mesmo método pode apresentar várias formas, de acordo com seu contexto. O polimorfismo é importante pois permite que a semântica de uma interface seja efetivamente separada da implementação que a representa. Por exemplo, o suponha a seguinte classe escrita em Java:
public abstract class OperacaoMatematica {
public abstract double calcular(double x, double y);
}
Está é uma classe abstrata que representa qualquer operação matemática. Podemos imaginar diversas operações que se encaixam na sua interface, como soma, subtração, multiplicação ou divisão, entre outras. Note que, embora que a natureza do cálculo mude, a semântica do método calcular não muda, ou seja, ele sempre calculará o resultado da operação matemática que está sendo trabalhada.
Definamos então, duas subclasses, Soma e Subtracao, que implementam a classe OperacaoMatematica:
public class Soma extends OperacaoMatematica {
public double calcular(double x, double y) {
return x+y;
}
}
public class Subtracao extends OperacaoMatematica {
public double calcular(double x, double y) {
return x-y;
}
}
O seguinte trecho de código demonstra o uso do polimorfismo:
public class Contas {
public double mostrarCalculo(OperacaoMatematica operacao, double x, double y) {
system.out.println("O resultado é: " + operacao.calcular(x, y);
}
public static void main(String args[]) {
//Primeiro calculamos uma soma
this.mostrarCalculo(new Soma(), 5, 5); //Imprime o resultado é: 10
this.mostrarCalculo(new Subtracao(), 5, 5); //Imprime o resultado é: 0
}
}
Note que, embora o método calcular tenha sido chamado duas vezes no interior de mostrarCalculo, o comportamento apresentado variou de acordo com a classe ao qual ele representava no momento.
Clareza e manutenção do código
Em linguagens de programação não polimorficas, para implementar o método mostrarCalculo, seria necessário recorrer a uma enumeração com o tipo de operação e, dentro do método, testar o valor da enumeração com um case, como no exemplo abaixo:
public void mostrarCalculo (int operacao, double x, double y) {
System.out.print("O resultado é: ");
switch (operacao) {
case SOMA:
System.out.print(""+(x+y));
break;
case SUBTRACAO:
System.out.print(""+(x-y));
break;
//... outras operacoes
default: throw new UnsupportedOperationException()
}
}
Além do código ser maior e mais difícil de ler, essa implementação tem outros problemas. Provavelmente esse não será o único método a utilizar operações matemáticas e, portanto, pode-se esperar não um, mas vários switchs como esse pelo código. O que acontece, então, se uma nova operação for adicionada ao sistema? Será necessário que todos os switchs sejam encontrados e substituídos. Com o polimorfismo, a modificação restringiria-se apenas a criação de uma nova classe.
Divisão da complexidade
Com o polimorfismo pode-se separar métodos genéricos de métodos mais específicos, dividindo a aplicação de acordo com o seu grau de abstração. Bibliotecas que usam esse recurso (herança+polimorfismo) são chamadas Frameworks. Exemplos de frameworks conhecidas sao a VCL do Delphi, o Swing do Java e o Eclipse.
Aplicações flexíveis
O polimorfismo combinado à reflexão permite facilmente a criação de plugins. A aplicacao original cria interfaces e classes que tem muito conhecimento semântico, mas a sua implementacao efetiva ficará a cargo de terceiros. Uma aplicacao gráfica, por exemplo, poderia ser implementada de forma a desenhar linhas, formas e gráficos precisos de acordo com operacões matemáticas fornecidas. Enquanto isso, empresas terceiras, nos diversos campos de sua atuação, implementariam as operações matemáticas exatas para o seu empreendimento (calculos de órbitas para astrônomia, calculos estruturais para engenharia civil, balística para aeronáutica, etc).
Polimorfismo e padrões de projeto
Boa parte dos padrões de projeto de software baseiam-se no uso de polimorfismo, por exemplo: Abstract Factory, Composite, Observer, Strategy, Template Method, etc.