C# - Aplicando conceitos OOP e Polimorfismo na prática


  Hoje vamos aplicar 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 é aplicar os conceitos em uma aplicação prática.

Neste artigo vamos criar 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 3 principais pilares do paradigma da POO.

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

Vamos criar 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 a mais simples e aderente ás boas práticas e ao paradigma da POO.

O primeiro conceito que vamos usar será a herança e para isso vamos iniciar criando uma classe abstrata onde vamos definir uma propriedade abstrata chamado 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 definda 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 a 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

Vamos agora implementar 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:

A seguire temos 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:

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

Executando o projeto iremos obter o resultado é exibido abaixo:

Temos assim um exemplo de aplicação onde aplicamos os recursos de herança, polimorfismos e encapsulamento de forma a termos 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 :  CalcAreaPOO.zip

"Jesus respondeu: Na verdade, na verdade te digo que aquele que não nascer da água e do Espírito, não pode entrar no reino de Deus."
João 3:5

Referências:


José Carlos Macoratti