Back-End

22 fev, 2019

C# – Aplicando conceitos OOP e polimorfismo na prática

Publicidade

Hoje veremos conceitos do paradigma da orientação a objetos e polimorfismo em uma aplicação prática. A melhor forma de aprender os conceitos de uma linguagem de programação é aplicando seus conceitos.

Neste artigo criaremos uma aplicação para calcular a área de figuras geométricas aplicando conceitos importantes da programação orientada a objetos (POO), como: encapsulamento, herança e polimorfismo – os três principais pilares do paradigma da POO.

Se você não conhece nada sobre esses conceitos, acompanhe os artigos abaixo publicados sobre o assunto:

Criaremos uma aplicação Console chamada CalcAreaPOO usando o VS 2017 Community para calcular a área do quadrado, retângulo, triângulo e círculo, aplicando os conceitos da POO.

Existem muitas maneiras de implementar o cálculo dessas figuras geométricas e vamos usar uma abordagem mais simples e aderente às boas práticas e ao paradigma da POO.

O primeiro conceito que usaremos será a herança, e para isso começaremos criando uma classe abstrata onde definiremos uma propriedade abstrata chamada CalcularArea, que vai retornar o valor da área:

Observe que não definimos o acessor set, pois a área é somente leitura e não pode ser definida pelo usuário.

Poderíamos ter usado uma interface IForma e o resultado final seria o mesmo, mas usar uma classe abstrata neste contexto pode nos dar a opção de fornecer uma implementação padrão para um novo método:

A classe abstrata será a classe base a partir da qual iremos herdar e realizar a implementação da propriedade CalcularArea para cada figura geométrica para qual desejamos calcular a área.

Além disso temos as seguintes diferenças entre Classe abstrata e Interface:

  • 1 – Classes abstratas podem ter constantes, membros, stubs de métodos (métodos sem um corpo) e métodos definidos, enquanto interfaces só podem ter stubs de constantes e métodos
  • 2 – Métodos e membros de uma classe abstrata podem ser definidos com qualquer visibilidade, enquanto todos os métodos de uma interface devem ser definidos como públicos (eles são definidos por padrão)
  • 3 – Ao herdar uma classe abstrata, uma classe filha concreta deve definir os métodos abstratos, enquanto que uma classe abstrata pode estender outra classe abstrata e os métodos abstratos da classe pai não precisam ser definidos
  • 4 – Da mesma forma, uma interface que estende outra interface não é responsável pela implementação de métodos da interface pai. Isso ocorre porque as interfaces não podem definir nenhuma implementação
  • 5 – Uma classe filha só pode estender uma única classe (abstrata ou concreta), enquanto uma interface pode se estender ou uma classe pode implementar várias outras interfaces
  • 6 – Uma classe filha pode definir métodos abstratos com a mesma visibilidade, ou menos restritiva, enquanto uma classe que implementa uma interface deve definir os métodos com exatamente a mesma visibilidade (pública)

Agora a próxima tarefa será criar classes concretas que herdam da classe abstrata Forma e implemente a propriedade CalcularArea:

1 – Classe Quadrado

2 – Classe Retângulo

3 – Classe Triângulo

4 – Classe Círculo

Em todas as implementações estamos herdando a classe abstrata Forma e sobrescrevendo a propriedade CalcularArea para retornar o valor da área da respectiva forma.

Usando propriedades estamos encapsulando o nosso código e podemos incluir lógica extra nos get/set sem quebrar o código; temos ainda o recurso do data binding disponível se precisarmos dele.

A implementação de CalcularArea usa o recurso Expression Bodied Member que usa expressões lambdas tornando o código mais conciso e legível.

Estamos aplicando o conceito de polimorfismo de herança, onde Polimorfismo significa muitas formas. Na orientação a objetos você pode enviar uma mesma mensagem para diferentes objetos e fazê-los responder da maneira correta.

Você pode enviar a mensagem CalcularArea para cada objeto semelhante a uma forma e cada objeto vai se comportar de maneira diferente para atender à sua solicitação. No caso, calculando a área da respectiva figura.

Quando uma mesma mensagem pode ser processada de diferentes formas, temos um exemplo de polimorfismo.

Implementando a interface da aplicação Console

Implementaremos agora a interface da aplicação Console adotando princípios de boa prática de programação.

Vamos criar um menu de opções onde o usuário escolhe a forma para qual deseja calcular a área. O Fluxo será o seguinte:

  • 1. Solicita ao usuário para escolher a figura
  • 2. Cria a figura com base na escolha do usuário
  • 3. Exibe o resultado da área
  • 4. Volta ao menu e solicita uma nova escolha

No arquivo Program.cs inicialmente vamos definir uma enumeração para representar as opções do menu da nossa aplicação:

A seguir, no método Main() vamos usar a enumeração para apresentar o menu e obter a escolha do usuário realizando o cálculo e exibição da área da figura selecionada:

Abaixo temos o código do método GetEscolha(), que exibe as opções e processa a escolha do usuário:

A seguir temos o código do método GetDouble() que recebe a entrada do usuário e a converte para double, verificando se é um valor válido

Temos, também, o código das classes para criar cada uma das figuras conforme a escolha do usuário. A implementação solicita a informação do usuário para os dados necessários para calcular a área:

Todas as classes definidas acima retornam uma classe do tipo escolhido pelo usuário.

Executando o projeto iremos obter o resultado que é exibido abaixo:

Temos assim um exemplo onde aplicamos os recursos de herança, polimorfismos e encapsulamento de forma a resultar em um código legível e fácil de manter.

É claro que o código pode ser melhorado, mas chegamos a um resultado final bem ajustado.

Pegue o projeto aqui.

Referências