# Polimorfismo (ciência da computação)

Na programação orientada a objetos, o polimorfismo permite que referências de tipos de classes mais abstratas representem o comportamento das classes concretas que referenciam. Assim, é possível tratar vários tipos de maneira homogênea (através da interface do tipo mais abstrato). O termo polimorfismo é originário do grego e significa "muitas formas" (poli = muitas, morphos = formas).
O polimorfismo é caracterizado quando duas ou mais classes distintas têm métodos de mesmo nome, de forma que uma função possa utilizar um objeto de qualquer uma das classes polimórficas, sem necessidade de tratar de forma diferenciada conforme a classe do objeto.
Uma das formas de implementar o polimorfismo é através de uma classe abstrata, cujos métodos são declarados mas não são definidos, e através de classes que herdam os métodos desta classe abstrata.

## Tipos de polimorfismo

Existem quatro tipos de polimorfismo que a linguagem pode ter (atente para o fato de que nem toda linguagem orientada a objeto tem implementado todos os tipos de polimorfismo):
* Universal
** Inclusão - um ponteiro para classe mãe pode apontar para uma instância de uma classe filha (exemplo em Java: List lista = new LinkedList; (tipo de polimorfismo mais básico que existe)
** Paramétrico - se restringe ao uso de templates (C++, por exemplo) e generics (C#/Java)
* Ad-Hoc
** Sobrecarga - duas funções/métodos com o mesmo nome mas assinaturas diferentes
** Coerção - conversão implícita de tipos sobre os parâmetros de uma função

## Exemplos

Suponha a seguinte classe escrita em Java:
Esta é 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, mesmo 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 extendem a classe OperacaoMatematica:
O seguinte trecho de código demonstra o uso do polimorfismo:
Embora o método calcular tenha sido chamado duas vezes no interior de mostrarCalculo, os tipos (isto é, as classes das instâncias) utilizados como parâmetros eram diferentes. De fato, o comportamento de cada tipo era exatamente oposto. É comum definir sobrecarga de métodos ou simplesmente sobrecarga como uma forma de polimorfismo (chamado de polimorfismo ad-hoc). Nesse caso, implementa-se métodos com um mesmo nome, mudando apenas a lista de parâmetros que ele recebe. Digamos
Embora nesse caso o resultado possa ser o mesmo que aquele obtido com o uso de herança, no polimorfismo ad-hoc não existem garantias que os métodos sobrecarregados tenham o mesmo comportamento.

## Benefícios do polimorfismo
### Clareza e manutenção do código

Em linguagens de programação não-polimórficas, 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, como no exemplo abaixo:
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. Se uma nova operação for adicionada ao sistema, será necessário que todos os switchs sejam encontrados e substituídos, por exemplo. Com o polimorfismo, a modificação restringiria-se apenas à criação de uma nova classe.

## Polimorfismo e padrões de projeto

Boa parte dos padrões de projeto de software baseia-se no uso de polimorfismo, por exemplo: Abstract Factory, Composite, Observer, Strategy, Template Method etc;
O polimorfismo também é usado em uma série de refatorações, como substituir condicional por polimorfismo.