Polimorfismo é a técnica que permite implementar um método numa classe que tenha o comportamento diferente do método na sua classe ancestral. Podemos entender como um exemplo um objeto chamado Automóvel, que tem dois descendentes: Carro e Moto.
O Objeto Automóvel tem um método chamado ligar, que todo automóvel possui. Os objetos Carro e Moto também têm o método ligar, porém com implementações diferentes entre si.
Vamos fazer alguns códigos:
Delphi:
interface
type
TAutomovel = class
public
procedure Ligar;
end;
TCarro = class(TAutomovel)
public
procedure Ligar; override;
end;
TMoto = class(TAutomovel)
public
procedure Ligar; override;
end;
implementation
procedure TAutomovel.Ligar;
begin
{implementação do método Ligar da classe TAutomovel}
end;
procedure TCarro.Ligar;
begin
{a palavra chave inherited indica que este método vai incluir a
implementação do método do ancestral no ponto em que foi inserida}
inherited;
{implementação do método Ligar da classe TCarro}
end;
procedure TMoto.Ligar;
begin
{a palavra chave inherited indica que este método vai incluir a
implementação do método do ancestral no ponto em que foi inserida}
inherited;
{implementação do método Ligar da classe TMoto}
end;
Java:
class Automovel {
pubic void ligar() {
// implementação do método ligar da classe Automovel
}
}
class Carro extends Automovel {
public void ligar() {
// o método super() chama a implementação do método da classe
// ancestral no ponto em que foi iserido
super();
// implementação do método ligar da classe Carro
}
}
class Moto extends Automovel {
public void ligar() {
// o método super() chama a implementação do método da classe
// ancestral no ponto em que foi iserido
super();
// implementação do método ligar da classe Moto
}
}
C#
class Automovel {
public void ligar() {
// implementação do método ligar da classe Automovel
}
}
class Carro : Automovel {
public override void ligar() {
// a chamada a base.chama a implementação do método da classe
// ancestral no ponto em que foi iserido
base.ligar();
// implementação do método ligar da classe Carro
}
}
class Moto : Automovel {
public override void ligar() {
// a chamada a base.chama a implementação do método da classe
// ancestral no ponto em que foi iserido
base.ligar();
// implementação do método ligar da classe Moto
}
}
Outra forma de polimorfismo é quando a classe ancestral tem um método mas não faz nenhuma implementação, deixando-a por parte das suas classes descendentes. Este tipo de método é chamado abstrato. Neste caso a classe derivada é obrigada a fazer sua própria implementação do método.
Vou abrir um pequeno parêntesis para falar sobre 'abstratos' em POO.
Geralmente métodos e classes abstratas apenas repredentam a idéia e não a funcionalidade. Vamos a exemplos:
Classes abstratas não podem ser instanciadas.
O quê? Como assim? Por que ter classe se eu não posso instanciá-la?
Uma das principais vantagens de se usar classes abstratas é que nos permite introduzir comportamento comum aos descendentes.
Vamos a um exemplo prático: Figuras geométricas. O que é exatamente uma figura geométrica? Nós não temos uma resposta concreta porque figura geométrica é um objeto abstrato. Mas quanto a quadrado? Retângulo? Losango? Estes são figuras geométricas que podemos descrever claramente.
Todas as figuras geométricas têm um método chamado 'desenhar', mas as implementações são diferentes entre as figuras. É aí que entram a classe abstrata e o método abstrato.
Classes abstratas não podem ser instanciadas. Por um motivo bem simples: Porque são abstratas! Hehe... A classe só tem uma estrutura básica para servir de base para as suas classes descendentes.
Por exemplo, a classe FiguraGeometrica tem o método abstrato Desenhar, que aceita como argumentos as coordenadas de onde ele vai começar a ser desenhado (x e y). Todos os seus descendentes terão este método, mas cada um deles deve ter sua própria implementação.
Delphi
type
TFiguraGeometrica = class
public
procedure Desenhar(const x, y: Integer); virtual;
end;
TQuadrado = class(TFiguraGeometrica)
public
procedure Desenhar(const x, y: Integer); override;
end;
TLosango = class(TFiguraGeometrica)
public
procedure Desenhar(const x, y: Integer); override;
end;
...
procedure MontarFigura(Figura: TFiguraGeometrica; const x, y: Integer);
begin
Figura.Desenhar(x, y);
end;
Java
abstract class FiguraGeometrica {
abstract void desenhar(int x, int y);
}
class Quadrado extends FiguraGeometrica {
public void desenhar(int x, int y) {
// implementação do método desenhar do objeto Quadrado
}
}
class Losango extends FiguraGeometrica {
public void desenhar(int x, int y) {
// implementação do método desenhar do objeto Losango
}
}
...
void montarFigura(FiguraGeometrica figura, int x, int y) {
figura.desenhar(x, y);
}
C#
abstract class FiguraGeometrica {
public abstract void desenhar(int x, int y);
}
class Quadrado : FiguraGeometrica {
public override void desenhar(int x, int y) {
// implementação do método desenhar do objeto Quadrado
}
}
class Losano : FiguraGeometrica {
public override void desenhar(int x, int y) {
// implementação do método desenhar do objeto Losango
}
}
...
public void montarFigura(FiguraGeometrica figura, int x, int y) {
figura.desenhar(x, y);
}
Mas Felipeeee... que efeito prático isso vai ter na aplicação?
Desta forma nós evitamos redundância no nosso código, 'if' que não precisamos... Quando executamos o método MontarFigura nós passamos qualquer objeto derivado da classe FiguraGeometrica que, pelo fato dela ser abstrata (virtual em delphi) ela vai executar o método da classe derivada correspondente. Maneiro, né...
Esse post acabou sendo mais longo que eu esperava, mas espero que o conteúdo postado tenha sido bem absorvido. Abraços.
Guri vlw, amanhã eu tenho Avaliação de POO na facul, e vc me ajudou bastante a entender Polimorfismo!
ResponderExcluirmuito obrigada!