Artigo Clube Delphi 75 - POO no Delphi

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (1)  (0)

Artigo da Revista Clube Delphi Edição 75.

Esse artigo faz parte da revista Clube Delphi Edição 75. Clique aqui para ler todos os artigos desta edição

imagem_pdf.jpg

POO

Programação Orientada a Objetos no Delphi

Conceitos e Implementação – Parte II

 

No artigo da edição anterior iniciamos a apresentação de alguns dos principais conceitos da programação orientada a objetos (POO) no Delphi, abordando classes, atributos, métodos, encapsulamento e herança. Estes conceitos foram apresentados através de exemplos a partir de um modelo de classes representando departamentos e seus funcionários, de diferentes tipos. Este artigo complementa o anterior abordando outros importantes conceitos de POO como polimorfismo, associação e interfaces, além de apresentar um estudo de caso que se utiliza dos conceitos apresentados em ambos os artigos, mostrando como podem ser utilizados na prática.

 

Polimorfismo

O polimorfismo é uma característica da Orientação a Objetos que permite aos objetos das classes terem comportamentos diferentes, sejam de seus ancestrais, da própria classe ou mesmo de outras classes. Assim, os métodos definidos e implementados em classes ancestrais, podem ser redefinidos e reimplementados em classes descendentes.

Para que isso funcione adequadamente, é necessário garantir qual implementação de um método será executada, visto que pode existir mais de uma com o mesmo nome, seja na hierarquia ou dentro da própria classe. Dessa forma o Delphi oferece um conjunto de palavras reservadas que permitem definir o comportamento das chamadas de métodos, ou seja, a ligação da chamada com a implementação desejada.

De acordo com sua forma de ligação, os métodos podem ser classificados em três tipos: static, virtual e dynamic. Os métodos estáticos (static) são o padrão do Delphi, ou seja, caso não sejam utilizadas explicitamente as diretivas virtual ou dynamic, os mesmos são considerados estáticos. A chamada desses tipos de métodos ativa a implementação feita na classe que instanciou o objeto.

Na hierarquia de funcionários, onde estão definidos os métodos polimórficos CalcularSalario e CalcularPremio, ainda não foram aplicadas diretivas nos métodos modificando o seu tipo e, por isso, os mesmos são estáticos.

Durante a execução do sistema, variáveis podem receber objetos criados a partir de classes diferentes do tipo declarado, uma vez que estejam numa mesma hierarquia. Dessa forma a ativação dos métodos ocorre de maneira diferente entre os objetos. Isso ocorre porque para métodos estáticos, a implementação ativada é a correspondente da classe que define a variável e não da classe que define sua instância.

Tal comportamento pode ser modificado para métodos virtuais e dinâmicos, através do uso das diretivas virtual e dynamic, em conjunto com a diretiva override. Assim, a chamada dos métodos passa a ativar a implementação do tipo em tempo de execução, ou seja, de acordo com o tipo da instância e não o tipo definido para a variável.

O uso de override, garante que apenas uma implementação do método exista em tempo de execução nas classes descendentes, ocultando as implementações dos ancestrais. Porém, esses métodos devem ter exatamente a mesma assinatura, ou seja, mesmo nome do método e mesmo número, ordem e tipos dos parâmetros.

As diretivas virtual e dynamic são equivalentes, sendo diferentes no sentido de que a virtual otimiza a velocidade de acesso e dynamic otimiza o tamanho do código, sendo a virtual a forma mais comum e eficiente de implementar o polimorfismo. Na Listagem 1 demonstra-se o efeito do uso dessas diretivas, através de algumas modificações na hierarquia de Funcionario.

 

Listagem 1. Definição da hierarquia de Funcionario com método virtual

type

  Funcionario = class

    function CalcularSalario: real; virtual;

  end;

  FuncionarioMensalista = class (Funcionario)

    function CalcularSalario: real; override;

  end;

  FuncionarioDiarista = class (Funcionario)

    function CalcularSalario: real; override;

  end;

 

Na Listagem 1, utiliza-se na assinatura do método CalcularSalario na classe Funcionario, a diretiva virtual, enquanto que nas classes descendentes utiliza-se a diretiva override. As implementações dos métodos continuam as mesmas.

A Listagem 2 apresenta a utilização dos métodos com a diretiva override. Pressupõe-se que os valores dos campos dos objetos tenham sido modificados entre a criação dos objetos e a execução dos serviços CalcularSalario. A Listagem 2 deve ser implementada em outra unit que não a untClasses, devendo referenciá-la.

 

Listagem 2. Chamada de métodos virtuais com override

01: var

02:   Func1: Funcionario;

03:   Func2: FuncionarioDiarista;

04: begin

05:   {Funcionario 1}

06:   Func1 := FuncionarioMensalista.Create;

07:   Func1.CalcularSalario;

08:   {Funcionario 2}

09:   Func2 := FuncionarioDiarista.Create;

10:   Func2.CalcularSalario;

11: end;

 

Durante a execução do trecho de código apresentado na Listagem 2, as chamadas de métodos nas linhas 07 e 10 ativam a implementação correspondente das classes FuncionarioMensalista e FuncionarioDiarista respectivamente. Embora o tipo de dados da variável Func1 seja Funcionario (linha 02), o objeto armazenado nela é do tipo FuncionarioMensalista (linha 06). Sendo assim, em função da diretiva override, são executadas as implementações relativas às instâncias, e não relativas ao tipo da variável, como no caso dos métodos estáticos.

Vale a pena ressaltar que, para uso da diretiva override, a assinatura dos métodos deve ser exatamente igual, pois de outra forma é apresentado um erro durante a compilação. Além disso, override somente pode ser utilizado em conjunto com virtual ou dynamic, não podendo ser utilizado em métodos estáticos.

Para casos de polimorfismo onde a assinatura do método é diferente nos seus descendentes, podem ser utilizadas duas outras diretivas: overload e reintroduce.

A diretiva overload pode ser utilizada para qualquer tipo de método, seja estático, virtual ou dinâmico. Para métodos virtuais pode-se utilizar a diretiva reintroduce em conjunto para os descendentes. Além de permitir assinaturas diferentes de um mesmo método, a diretiva overload não oculta as implementações do método nos ancestrais, estando assim disponíveis mais de uma implementação simultaneamente.

Para ativar a implementação correta, são analisados os parâmetros utilizados na chamada do método, executando assim a implementação que corresponder a esses parâmetros. Porém, para os métodos virtuais, caso seja necessário, os métodos dos ancestrais podem ser ocultados, utilizando a diretiva reintroduce.

A Listagem 3 apresenta um exemplo do uso das diretivas overload e reintroduce. 

 

Listagem 3. Hierarquia com uso de overload e reintroduce

01: type

02:   Funcionario = class

03:     {Definições existentes}

04:     public

05:       function CalcularSalario: real;

06:       function CalcularPremio: real; virtual;

07:   end;

08:   FuncionarioMensalista = class (Funcionario)

09:     {Definições existentes}

10:     public

11:       function CalcularSalario(

            pHoraExtra: real): real; overload;

12:       function CalcularPremio(

            pTaxa: real): real; reintroduce;

13:   end;"

A exibição deste artigo foi interrompida :(
Este post está disponível para assinantes MVP

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?