Olá! Meu nome é Yasmin Araújo e faço parte do time da Escola de Programação.
Audiodescrição: Yasmin é uma mulher branca, com cabelo castanho escuro na altura dos ombros. Ela veste uma blusa rosa e, ao fundo, há uma parede iluminada com luz azul.
Neste curso, nós vamos trabalhar com polimorfismo, que é o último pilar da orientação a objetos.
Para começar, vamos explorar o conceito de polimorfismo, tanto pela definição quanto pela prática, e como podemos utilizá-lo em C#. Em seguida, trabalharemos com os diferentes tipos de polimorfismo. Vamos analisar o polimorfismo de sobrecarga, o polimorfismo de sobrescrita e, por fim, o polimorfismo de subtipos.
Aqui, temos uma variedade de termos técnicos, mas, ao longo das nossas práticas, veremos que todos esses conceitos são bastante fáceis de aplicar no dia a dia. Portanto, não há motivo para preocupação. Vamos começar?
Para compreendermos o polimorfismo, precisamos primeiro entender o significado dessa palavra. Podemos dividir "polimorfismo" em duas partes: "poli" e "morfismo". "Poli" significa muitos, e "morfismo" está relacionado a formas. Note que temos a mesma grafia, mas a palavra está um pouco alterada. Ao juntarmos as duas partes, obtemos que polimorfismo significa "muitas formas".
Como assim, muitas formas? No mundo real, existem várias situações em que podemos realizar uma determinada ação de maneiras diferentes. O polimorfismo nos ajuda a representar essas diferentes formas em nosso código. Mas como isso funciona? Vamos exemplificar no nosso contexto.
Na classe Produto
, estamos trabalhando com o desconto no preço desse produto. Utilizamos a porcentagem, ou seja, passamos uma porcentagem como parâmetro do método, e o preço é multiplicado por essa porcentagem para obter um desconto final.
Preco = Preco * (1 - desconto/100);
No entanto, existe outra forma de aplicar um desconto, que é passando um valor fixo a ser subtraído do preço. Por exemplo, podemos ter R$10 de desconto no produto, realizando a subtração para obter o resultado final. Assim, temos duas formas de fazer a mesma coisa: aplicar o desconto. Queremos representar essa situação no nosso código. Como fazemos isso? Utilizando o polimorfismo.
Para implementar isso, é bastante simples. Criamos um novo método com o mesmo nome, mas com parâmetros diferentes. No Visual Studio, criamos um public void
chamado AlterarPrecoComDesconto
, passando um valor inteiro, pois geralmente não utilizamos valores fracionados para fornecer esse desconto.
public void AlterarPrecoComDesconto(int desconto)
{
Preco = Preco - desconto;
}
Observe que o compilador não apresenta problemas, pois estamos realizando ações diferentes, mesmo que tenham o mesmo nome. A ideia é que o método tenha o mesmo nome dentro da mesma classe, mas com parâmetros diferentes. No primeiro caso, usamos um double
, e no segundo, um int
. Se tivéssemos, por exemplo, dois métodos com double desconto
, o compilador reclamaria, pois não conseguiria diferenciar. Se tivéssemos uma quantidade diferente de parâmetros, ele conseguiria fazer essa distinção. Vamos ver um exemplo disso também.
Portanto, a ideia é ter o mesmo método, com o mesmo nome, mas com parâmetros diferentes dentro da mesma classe. Quando trabalhamos com polimorfismo dessa forma, estamos lidando com polimorfismo de sobrecarga.
O polimorfismo de sobrecarga é amplamente aplicado em construtores, pois desejamos inicializar nossas classes de maneiras diferentes. No exemplo de um produto físico, o estoque é inicialmente definido como zero.
public ProdutoFisico(string nome, string descricao,
decimal preco, string imagem)
: base(nome, descricao, preco, imagem)
{
this.Estoque = 0;
}
No entanto, podemos querer inicializar um produto com um valor específico de estoque. Para isso, podemos criar um novo construtor para diferenciar essas duas inicializações.
public ProdutoFisico(string nome, string descricao,
decimal preco, string imagem, int estoque)
: base(nome, descricao, preco, imagem)
{
this.Estoque = estoque;
}
Dessa forma, o compilador não apresenta mais erros, e estamos utilizando o polimorfismo de sobrecarga.
Podemos ver a aplicação dos métodos ao construir um produto físico com estoque zerado. Ao executar, verificamos que o estoque é zero.
ProdutoFisico item1 = new ProdutoFisico("Teclado", "Modelo compacto e silencioso" +
"perfeito para produtividade diária.",
80.00m, "Imagem");
Console.WriteLine(@$"Dados do item 1:
Nome: {item1.Nome};
Descricao: {item1.Descricao};
Preco: {item1.Preco};
Estoque: {item1.Estoque};
");
Em seguida, copiamos o produto físico item1
e criamos item2
, inicializando-o com um estoque de 20.
ProdutoFisico item2 = new ProdutoFisico("Teclado", "Modelo compacto e silencioso" +
"perfeito para produtividade diária.",
80.00m, "Imagem", 20);
Console.WriteLine(@$"Dados do item 2:
Nome: {item2.Nome};
Descricao: {item2.Descricao};
Preco: {item2.Preco};
Estoque: {item2.Estoque};
");
Além disso, alteramos o preço utilizando duas formas de desconto. Para o item1
, aplicamos um desconto de 10% passando 10.0M
e, em seguida, imprimimos o preço atualizado.
item1.AlterarPrecoComDesconto(10.0m);
Console.WriteLine(item1.Preco);
Depois, aplicamos um desconto de 10 unidades inteiras e imprimimos novamente.
item1.AlterarPrecoComDesconto(10);
Console.WriteLine(item1.Preco);
Ao executar o código, observamos que o estoque do item1
é zero e o do item2
é 20, confirmando as duas inicializações. As duas formas de aplicar desconto também funcionam corretamente: o produto inicialmente custava R$ 80,00, foi para R$ 72,00 com 10% de desconto e, depois, para R$ 62,00 com um desconto de R$ 10,00.
Dessa forma, vemos o polimorfismo de sobrecarga em ação. Existe ainda outra forma de trabalhar com polimorfismo em métodos, que será abordada na sequência.
Para discutirmos sobre outro tipo de polimorfismo em métodos, vamos considerar a seguinte situação: temos nossos produtos físicos, que podem ser entregues. Assim, criaremos dentro de produto físico um método chamado entregar
, que receberá um endereço. Teremos um public void entregar
e, para entregar, passaremos uma string endereço como parâmetro. A ideia da entrega será apenas imprimir que o produto está sendo entregue. Podemos utilizar Console.WriteLine
, calculando a rota com base no endereço e enviando o produto. Utilizaremos interpolação para incluir o nome do nosso produto, resultando na entrega do produto físico. Aqui, estamos apenas utilizando implementações de teste.
Entregar
para Produtos FísicosVamos começar definindo o método Entregar
na classe de produto físico:
public void Entregar(string endereco)
{
}
Agora, vamos adicionar a lógica para imprimir a mensagem de entrega, utilizando interpolação de strings para incluir o nome do produto:
public void Entregar(string endereco)
{
Console.WriteLine($"Calculando frete com base no {endereco} e enviando {Nome}");
}
Entregar
para Produtos DigitaisConseguimos entregar produtos físicos, mas, ao pensarmos em produtos digitais, também é possível realizar entregas. A entrega de um produto digital também requer um endereço, mas, neste caso, será um endereço eletrônico, pois desejamos enviar o produto digital para o e-mail do cliente. Vamos copiar nosso método entregar
e aplicá-lo ao produto digital. Logo após o método estáExpirado
, colaremos o método copiado e faremos as adaptações necessárias. Teremos uma string endereço e, em vez de calcular uma rota, queremos simplesmente enviar o nome do produto para o e-mail. Colocaremos o endereço de e-mail fornecido pelo usuário. Com isso, conseguimos realizar a entrega de um produto digital.
Para o produto digital, o método Entregar
será assim:
public void Entregar(string endereco)
{
Console.WriteLine($"Enviando {Nome} para o email {endereco}");
}
Entregar
na Classe ProdutoAo observarmos, notamos que temos um método entregar
tanto em produto digital quanto em produto físico. Se esse método está presente nas duas classes, podemos afirmar que nossos produtos sempre serão entregues. Assim, podemos querer incluir esse comportamento na nossa classe produto. Sempre que adicionarmos um novo tipo de produto, desejaremos entregá-lo de alguma forma. Para indicar que esse comportamento é genérico, adicionaremos o método entregar
na classe produto. Teremos um public void entregar
.
Aqui, notamos uma diferença: ao observarmos os métodos avaliar
e alterarPreçoComDesconto
, percebemos que eles estão na classe produto e são como cópias para as classes produto físico e produto digital, como se fossem replicados diretamente durante a herança. No caso do entregar
, não é isso que desejamos. O método entregar
existirá na classe produto, mas as implementações serão diferentes dentro de produto físico e produto digital. Portanto, não queremos implementar de fato o método entregar
na classe produto, pois um produto genérico não é entregue; apenas produtos físicos e digitais, que são classes concretas, são entregues.
Entregar
Dessa forma, podemos afirmar que o método entregar
na classe produto será abstrato, sendo implementado apenas nas classes concretas. É semelhante ao que fazemos com métodos em interfaces, onde apenas declaramos os métodos e os implementamos posteriormente. Para isso, utilizaremos a palavra-chave abstract
no nosso método entregar
, passando também o parâmetro string endereço. Assim, todas as classes que herdam de produto serão obrigadas a implementar o método entregar
.
public abstract void Entregar(string endereco);
Override
para ImplementaçãoNo momento, o produto físico está apresentando erro, indicando que não implementamos o método entregar
, mas ele já está implementado.
Por que estamos enfrentando esse erro? Isso ocorre porque precisamos da palavra-chave override
. Toda vez que usamos essa palavra, estamos indicando que nosso método está sendo sobrescrito na classe filha. Ao lado da linha 24, há um "O" e uma seta para cima, semelhante ao que tínhamos nas interfaces, indicando que estamos pegando um método herdado e sobrescrevendo-o na classe filha. No caso de produto digital
, também precisamos utilizar a palavra-chave override
. Assim, conseguimos ter um método genérico, abstrato, chamado entregar
, e implementá-lo em cada uma das classes filhas.
public override void Entregar(string endereco)
{
Console.WriteLine($"Calculando frete com base no {endereco} e enviando {Nome}");
}
public override void Entregar(string endereco)
{
Console.WriteLine($"Enviando {Nome} para o email {endereco}");
}
Quando utilizamos a palavra override
, estamos indicando que o método está sendo sobrescrito. Por isso, esse tipo de polimorfismo é chamado de polimorfismo de sobrescrita. A ideia é ter um método declarado na classe genérica e reimplementá-lo, sobrescrevendo-o nas classes filhas, que são produto digital
e produto físico
, no nosso caso.
Virtual
Além dos métodos abstratos, podemos querer fornecer implementações padrão para nossos métodos nas classes mães. No caso do método entregar
, por exemplo, poderíamos querer definir uma entrega padrão. Poderíamos fazer um console.writeLine
para uma entrega genérica, apenas para visualização. Fazendo isso, enfrentamos um problema, pois o método não é mais abstrato. Precisamos remover o abstract
, e assim temos uma implementação padrão. No entanto, se voltarmos para produto físico
ou produto digital
, eles começarão a apresentar erros. Isso ocorre porque não está sinalizado de forma alguma, dentro da classe produto
, que o método entregar
pode ser sobrescrito. Precisamos usar outra palavra-chave, que é virtual
, para indicar que podemos sobrescrever o método nas classes filhas. Uma vez que usamos virtual
, podemos usar override
nas classes produto físico
e produto digital
sem problemas.
public virtual void Entregar(string endereco)
{
Console.WriteLine("Entrega genérica");
}
Program.cs
Aqui temos uma diferença: podemos sobrescrever nosso método se ele for do tipo abstrato e não tiver nenhuma implementação. É importante lembrar que só conseguimos trabalhar com métodos abstratos dentro de classes abstratas. Se não temos métodos abstratos, mas apenas métodos já implementados, precisamos marcá-los como virtuais para que possam ser sobrescritos.
Para visualizar como isso está funcionando, vamos para a classe Program.cs
. Nessa classe, temos um item 1
, que é um produto físico
, e um item 2
, que é um produto digital
. Podemos chamar item 1.Entregar
e passar um endereço físico. Podemos chamar o mesmo método em item 2
, que também será Entregar
, mas passaremos um e-mail, como "iasmin.com". Fazendo isso, temos duas entregas. Estamos chamando o método Entregar
, mas são os mesmos métodos com o mesmo tipo de parâmetro, ou seja, têm a mesma assinatura, mas pertencem a classes diferentes. No final, a implementação desses métodos será diferente.
item1.Entregar("endereço físico");
item2.Entregar("iasmin@gmeil.com");
Vamos executar para ver o resultado. A compilação está sendo executada. Ao lado, temos nossos dados. A primeira entrega foi "calculando o frete e enviando o teclado", e agora "enviando o curso para o e-mail iasmin.com". Vamos apenas adicionar um "A" aqui. Feito isso, visualizamos essas duas entregas de formas diferentes, o que é mais um tipo de polimorfismo.
O curso Praticando C#: orientação a objetos com polimorfismo possui 29 minutos de vídeos, em um total de 20 atividades. Gostou? Conheça nossos outros cursos de .NET em Programação, ou leia nossos artigos de Programação.
Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:
Impulsione a sua carreira com os melhores cursos e faça parte da maior comunidade tech.
1 ano de Alura
Assine o PLUS (1 ANO) e garanta:
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você tem acesso a eventos exclusivos, grupos de estudos e mentorias com especialistas de diferentes áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Acelere o seu aprendizado com a IA da Alura e prepare-se para o mercado internacional.
1 ano de Alura
Todos os benefícios do PLUS (1 ANO) e mais vantagens exclusivas:
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos, corrige exercícios e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com a Luri até 100 mensagens por semana.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Transforme a sua jornada com benefícios exclusivos e evolua ainda mais na sua carreira.
1 ano de Alura
Todos os benefícios do PRO (1 ANO) e mais vantagens exclusivas:
Mensagens ilimitadas para estudar com a Luri, a IA da Alura, disponível 24hs para tirar suas dúvidas, dar exemplos práticos, corrigir exercícios e impulsionar seus estudos.
Envie imagens para a Luri e ela te ajuda a solucionar problemas, identificar erros, esclarecer gráficos, analisar design e muito mais.
Brinde aniversário Alura
Escolha os ebooks da Casa do Código, a editora da Alura, que apoiarão a sua jornada de aprendizado para sempre.
Enquanto durarem os estoques