Artigo Clube Delphi 75 - POO no Delphi

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

Clique aqui para ler esse artigo em PDF.

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.

" [...] continue lendo...

Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados