C# - Polimorfismo (revisão)


Conceitos - Herança, Encapsulamento e Polimorfismo
 

Existem alguns conceitos básicos que estão vinculados ao conceito da programação orientada a objetos. São eles :

A herança permite implementar a funcionalidade a sua classe de tomar emprestado o resto da estrutura e comportamento de classes de nível mais alto.

Pensemos em uma classe carro.

 

Esta classe define os comportamentos e atributos de um carro; E existem atributos que serão comum a todos os carros.

 

As rodas e o motor são atributos comuns a qualquer carro. Já uma Ferrari possui atributos que somente ela possui : valor e potência por exemplo.

 

A definição formal para herança seria:

- Herança é um mecanismo que permite que características comuns a diversas classes sejam agrupadas em uma classe base, ou superclasse. A partir de uma classe base, outras classes podem ser especificadas.
- Cada
classe derivada ou subclasse apresenta as características (estrutura e métodos) da classe base e acrescenta a elas o que for definido de particularidade para ela

 

Encapsular significa "ocultar informações"  ele define que cada objeto contém todos os detalhes de implementação necessários sobre como ele funciona e oculta os detalhes internos sobre como ele executa os serviços.

 

Quando você acelera um carro você esta enviando uma mensagem ao motor do carro usando o acelerador e o carro sabe que tem que acelerar.

 

Você não precisa saber como é feita a aceleração no motor você apenas pisa fundo no acelerador, a implementação de como é feita a aceleração esta encapsulada do cliente.

 

Voltando a classe carro podemos aplicar o encapsulamento definindo propriedades na classe de forma que o acesso a seus atributos possa ser feito somente acessando as propriedades.

 

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 mover para cada objeto semelhante a um veiculo e cada um vai se comportar de maneira diferente para atender a sua solicitação.

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

 

Uma definição mais formal diria:

 

"Polimorfismo é o princípio pelo qual duas ou mais classes derivadas de uma mesma superclasse podem invocar métodos que têm a mesma identificação (assinatura) mas comportamentos distintos, especializados para cada classe derivada, usando para tanto uma referência a um objeto do tipo da superclasse"

Usando polimorfismo podemos :

  1. Invocar métodos da classe derivada através da classe base em tempo de execução;
  2. Permitir que classes forneçam diferentes implementações de métodos que são chamados com o mesmo nome;

Existem dois tipos básicos de polimorfismo:

  1. Polimorfismo em tempo de compilação (Overloading/Sobrecarga);
  2. Polimorfismo em tempo de execução (Overriding/Sobrescrita);

O polimorfismo em tempo de compilação utiliza a sobrecarga de métodos e operadores sendo também chamado de ligação precoce (early binding). A utilização da sobrecarga de métodos realiza a tarefa com distintos parâmetros de entrada.

 

O polimorfismo em tempo de execução pode ser feito usando herança e métodos virtuais. Quando sobrescrevemos(override) os métodos virtuais estamos alterando o comportamento dos métodos para a classe derivada. Isto também é conhecido como ligação tardia (late binding).

 

Vamos agora passar para prática essa teoria...

 

Prática 1 - Polimorfismo com herança e métodos virtuais

Pegando 'carona' no exemplo da classe carro vamos aumentar a abstração do exemplo e aplicar os conceitos de polimorfismo.

 

Imagine uma classe veículo que define os comportamentos e atributos de qualquer veículo e não apenas de carros.

 

Uma característica básica de qualquer veículo é o movimento logo nossa classe veículo pode expressar isso através de um método Mover().

 

Outra característica básica de qualquer veículo seria poder parar afinal nenhum veículo fica eternamente em movimento e isso seria expresso na classe veículo por um método Parar().

 

Então podemos criar uma classe Veiculo contendo esses métodos e usar o mecanismo da herança para que outras classes herdem os atributos e comportamentos comuns.

 

Vamos criar uma classe Veiculo , uma classe Automovel e uma classe Aeronave onde as duas últimas irão herdar da classe Veiculo e veremos como promover o polimorfismo usando o mecanismo da herança. Vemos isso representado no diagrama abaixo:

 

Seguindo essa orientação poderíamos vamos criar um novo projeto usando o Visual C# 2010 Express Edition do tipo Console Application com o nome CSharp_Polimorfismo;

 

No menu Project selecione o Item Add Class para criar as classes Veiculo, Aeronave e Automovel.

 

A seguir defina o código de cada classe conforme abaixo:

 

namespace CSharp_Polimorfismo1
{
    public class Veiculo
    {
        private string tipo;
        public string Tipo
        {
            get { return tipo; }
            set { tipo = value; }
        }

        public Veiculo(string tipoVeiculo)
        {
            this.tipo = tipoVeiculo;
        }
        public virtual void Mover()
        { }

        public virtual void Parar()
        { }
    }
}
using System;

namespace CSharp_Polimorfismo1
{
  public class Automovel : Veiculo
  {
       public Automovel(string tipoVeiculo)
         : base(tipoVeiculo)
      { }

     public override void Mover()
     {
        Console.WriteLine("Acelerando o veículo");
     }
     public override void Parar()
     {
        Console.WriteLine("Estou brecando o veículo.");
     }
   }
}
using System;

namespace CSharp_Polimorfismo1
{
  public class Aeronave : Veiculo
  {
       public Aeronave(string tipoVeiculo)
           : base(tipoVeiculo)
        { }

      public override void Mover()
      {
           Console.WriteLine("Decolando a aeronave");
      }
      public override void Parar()
      {
        Console.WriteLine("Estou aterrisando a aeronave.");
       }
    }
}
Veiculo.cs Automovel.cs Aeronave.cs

 

Na classe Veiculo temos:

  1. A propriedade pública Tipo que define o tipo de veículo
  2. O método virtual Mover() que define o comportamento Mover do veículo;
  3. O método virtual Parar() que define o comportamento Parar do veículo;
  4. O construtor da classe onde definimos o tipo de veículo;

O modificador de acesso virtual indica que o método pode ser sobrescrito na classe derivada.

Na classe Automovel temos:

  1. A classe Automovel herda da classe Veiculo;
  2. A classe Automovel sobrescreve os método Parar() e Mover() usando o modificador override;
  3. O construtor da classe Automovel executa o construtor da classe base;

Na classe Aeronave temos:

  1. A classe Aeronave herda da classe Veiculo;
  2. A classe Aeronave sobrescreve os método Parar() e Mover() usando o modificador override;
  3. O construtor da classe Aeronave executa o construtor da classe base;

Agora vamos definir o código para usar as classes e mostrar o comportamento de polimorfismo. Inclua o código abaixo na classe Program.cs no método Main():

using System;

namespace CSharp_Polimorfismo1
{
    class Program
    {
        static void Main(string[] args)
        {
            Veiculo[] veiculo = new Veiculo[2];

            veiculo[0] = new Automovel("Ferrari");
            veiculo[1] = new Aeronave("Tucano");

            MovimentarVeiculo(veiculo[0]);
            MovimentarVeiculo(veiculo[1]);

            Console.ReadKey();
        }

        public static void MovimentarVeiculo(Veiculo veiculo)
        {
            Console.WriteLine(veiculo.Tipo);
            veiculo.Mover();

        }
    }
}

No código cima temos :

- A criação de um vetor com dois elementos;
- A criação de duas instâncias, uma de Automovel e outra de Aeronave;
- A chamada do método MovimentarVeiculo que simula o movimento para cada veiculo;

Observe que no método MovimentarVeiculo estamos usando o método Mover() para cada tipo de veiculo que foi instanciado e cada objeto sabe realizar o movimento correto em resposta à mesma chamada do método.

Aqui estamos usando o conceito de polimorfismo pois o método Mover() é executado e a decisão de qual movimento será usado ocorre em tempo de exeucução;

Usamos veiculo.Mover() ao invés de Aeronave.Mover() ou Automovel.Mover().

Para usar o polimorfismo os objetos precisam executar as mesmas ações (métodos) mesmo que possuam comportamento diferente.

Prática 2 - Polimorfismo com sobrecarga de métodos

Vamos incluir um novo projeto na solução criada no item. Clique no menu File->Add->New Project e informe o nome Polimorfismo_SobrecargaMetodos;(Dessa forma teremos uma solução com dois projetos.)

Clique no menu Project->Add Class e informe o nome Calcular.cs e a seguir digite o código abaixo para a classe Calcular.

namespace Polimorfismo_SobrecargaMetodos
{
    class Calcular
    {
        public int Soma(int num1, int num2)
        {
            return (num1 + num2);
        }
       
        public int Soma(int num1, int num2, int num3)
        {
            return (num1 + num2 + num3);
        }
    }
}

Agora digite o código abaixo no arquivo Program.cs :


using System;

namespace Polimorfismo_SobrecargaMetodos
{
    class Program
    {
        static void Main(string[] args)
        {
            Calcular calc = new Calcular();
            Console.WriteLine("\nPolimorfismo com sobrecarga\n");
            Console.WriteLine("Somando 2 números...");
            Console.WriteLine(calc.Soma(45,43));
            Console.WriteLine("Somando 3 números...");
            Console.WriteLine(calc.Soma(45, 43, 100 ));
            Console.ReadKey();
        }
    }
}

A sobrecarga de métodos é um conceito onde usamos o mesmo nome do método muitas vezes na mesma classe, mas cada método com parâmetros diferentes. Com base nos parâmetros passados a execução é decidida em tempo de compilação.

Uma outra forma (mais elegante) de obter o mesmo resultado seria utilizando classes abstratas ou interfaces, mas isso é assunto para outro artigo...

Pegue o projeto completo aqui: CSharp_Polimorfismo1.zip

Rom 8:16 O Espírito mesmo testifica com o nosso espírito que somos filhos de Deus;
Rom 8:17
e, se filhos, também herdeiros, herdeiros de Deus e co-herdeiros de Cristo; se é certo que com ele padecemos, para que também com ele sejamos glorificados.

Rom 8:18
Pois tenho para mim que as aflições deste tempo presente não se podem comparar com a glória que em nós há de ser revelada.

Referências:


José Carlos Macoratti