Está en la página 1de 20

Introduo ao Mundo em Objetos em Delphi

Este um assunto bastante explorado, contudo, o mercado sempre se renova, novos profissionais surgem vidos por informao. Portanto neste artigo, abordarei os meandros da orientao por objetos na programao em Delphi. Costumo dizer que a orientao a objetos no a soluo para todos os problemas. H um ditado que retrata muito bem isto: "quando a nica ferramenta que temos na mo um martelo, tudo vira prego". A idia da OOP agregar a modelos de programao estruturados e modular paradigmas que trazem benefcios objetivos.

Pilares da OOP.

Classes e Objetos
Eu poderia aqui fazer uma grande dissertao acadmica falando de classes e objetos, os comparando a bolos, carros, pessoas etc.. Acredito que depois de mais de 30 anos ningum agenta mais tais analogias. Classes representam o prottipo para objetos em memria (instncia). Classes determinam todo o comportamento de um objeto, em outras palavras, um objeto uma representao fsica de uma classe, assim como uma edificao a representao de uma planta. A principal motivao que impulsiona a orientao por objetos a criao de classes que representam uma funcionalidade especfica, uma tarefa determinada, ou seja, para cada classe um objeto, para cada objeto uma responsabilidade, com isto, alcanamos o que chamamos de coeso. Uma classe deve possuir uma classe ancestral obrigatoriamente, contudo no Delphi no necessrio declarar esta herana explicitamente, pois qualquer classe quando declarada sem sua classe ancestral automaticamente herda da classe TObject, que a classe progenitora de todas as classes que compem a VCL (Visual Component Library).

Um prottipo de objeto (classe) pode ser composto de campos (Fields), propriedades (Property) e mtodos (procedures e functions). Toda classe deve possuir ao menos dois mtodos, um mtodo construtor e outro destrutor. Os mtodos construtores de uma classe so declarados atravs da palavra reservada constructor e geralmente so chamados de Create. Mtodos construtores so mtodos especializados, pois alocam toda a memria necessria criao (instanciao) de um objeto, retorna a referncia para este objeto, e o local recomendado para inicializao de campos, onde todos os membros so inicializados com nil ou string vazia. Dica: caso algo de errado acontea durante a construo do objeto constructor automaticamente seu mtodo destrutor ser invocado. Mas ao ser observado a estrutura do construtor na classe base TObject, ser constatado que o mesmo no possui instruo alguma:
constructor TObject.Create; begin end;

Todo construtor automaticamente chama o mtodo NewInstance da classe Tobject que invoca o mtodo InitInstance. Por sua vez, InitInstance usa a funo InstanceSize do objeto para determinar quanto em bytes necessrio para alocar memria para o objeto. Nunca o mtodo NewInstance ou InitInstance devero ser invocados diretamente.
class function NewInstance: TObject; virtual; class function InitInstance(Instance: Pointer): TObject; class function InstanceSize: Longint;

Observe que o mtodo NewInstance virtual, portanto pode ser sobreposto em situaes onde houver a necessidade de modificao da forma com os recursos (memria) so alocados. Uma vez que o NewInstance seja sobreposto para customizao da alocao de memria, o FreeInstance tambm dever ser sobreposto, pois os recursos alocados precisam ser dispensados. Contudo, no frigir dos ovos objetivamente, no o mtodo Create quem aloca memria diretamente, ele apenas um estimulador automtico dos mtodos NewInstance e InitInstance. O mtodo destrutor de uma classe tem um papel inverso ao construtor, sua tarefa desalocar os recursos que o construtor demandou. Todo mtodo destrutor de um objeto chama automaticamente o mtodo FreeInstance usa tambm o InstanceSize para dispensar a memria alocada pelo NewInstance para o objeto.

Contudo isto, se justifica que os mtodos construtor e destrutor de Tobject estejam vazios, pois so apenas encadeadores dos verdadeiros mtodos que realizam as tarefas de alocar e desalocar memria para os objetos.

Declaraes Forward
Freqentemente quando trabalhamos com classes comum nos depararmos com a situaes de mtua dependncia, ou seja, duas classes que fazem referncia uma as outras:
TClassA = class B: TclassB; End; TclassB = class A: TclassA; End; //erro aqui!

Um erro em tempo de desenvolvimento seria exibido, pois a classe TclassA usa (associao) a classe TclassB que est declara aps a classe, ou seja, o compilador ainda no tomou cincia da existncia da classe TclassB, pois a compilao top-down (de cima para baixo). Para resolver esta mtua dependncia, usamos uma declarao forward acima da classe TclassA:
TclassB = class; //declaracao forward TclassA = class B: TclassB; End; TclassB = class A: TclassA; End;

muito comum confundir declaraes forward com a de classes do tipo Tsample = class end. So coisas totalmente distintas.sdfsdfsdfsdfsdfsdfsdf.

Meta Classes
Meta Classes so estruturas referncia para classes, que podem ser utilizadas no cdigo para aumentar a flexibilidade. A declarao de um tipo referencia de classe feita atravs da diretiva class of.
TMetaCliente = class of TCliente;

Com isto, agora temos em TMetaCliente, uma referncia a classe TCliente, ou seja, TMetaCliente poder ser exigido em operaes que exijam o tipo da classe e no sua instancia. Observe este exemplo prtico:
type TBaseClass = class end; TMetaBaseClass = class of TBaseClass; TCliente = class(TBaseClass) Nome: string; end; TFuncionario = class(TBaseClass) Matricula: string; end;

Observe que o construtor pode ser invocado atravs de uma varivel referncia de classe.
function TForm1.GetObjectInstance(Meta: TMetaBaseClass): TBaseClass; begin result := Meta.Create; end;

Com isso podemos criar instancias de objetos genricos sem conhecer suas estruturas originais.
var Cliente: TCliente; Funcionario: TFuncionario; begin Cliente := GetObjectInstance(TCliente) as TCliente; Funcionario := GetObjectInstance(TFuncionario) as TFuncionario; end;

Herana
Herana realmente um mecanismo poderoso da orientao a objetos mas, objetivamente no a panacia tecnolgica. Neste observaremos que valorizam essa prtica e outras as quais ela trs prejuzos. Herana agrega evidente reaproveitamento de cdigo, onde verdadeiras estruturas codificadas podem se especializadas em uma nova classe. Quando falamos em herana dois termos precisam ser esclarecidos: Generalizao e Especializao.

Generalizao um grau de abstrao de alto nvel, representada atravs de classes que servem de base polimrfica e/ou de implementao para classes descendentes. No Delphi isto est presente em toda a arquitetura da VCL. TAnimal generalizao de todas as classes que descendem de TAnimal. A Generalizao pode ser classificada em trs tipos: disjunta, sobreposta, completa ou incompleta. Especializao a herana propriamente dita, quando reaproveitamos estruturas j declaradas por uma classe ancestral. TDog uma especializao de TAninal; A especializao de uma classe sempre total, ou seja, ao herdar de uma determinada classe, voc assumir todos os seus membros, sem exceo. Classes especializadas podem ganhar flexibilidade adicional quando usada associada a mtodos no estticos, que veremos em seguida. A arquitetura da linguagem Delphi no foi projetada de forma a permitir especializar mais de uma classe simultaneamente herana mltipla. Acredito que esta regra esteja em total conformidade com os paradigmas da orientao a objetos.

Herana por Associao


Como coloquei no incio do artigo, a herana no soluo para todos os problemas, o velho problema de martelos e pregos. A herana atribui ao cdigo uma dependncia forte entre as classes, o que chamamos de forte acoplamento, o que contradiz ao paradigma da orientao a objetos que prega que o cdigo deve Ter fraco acoplamento. Bom, o que isto significa objetivamente para o programador? Forte acoplamento se traduz e dependncias que refletem e diversos efeitos colaterais no cdigo fonte, aquelas pequenas correes ou at mesmo melhorias que encadeiam uma serie bugs em todo o projeto.

Efeitos colaterais so caracterizados por mudanas no cdigo que afetam o funcionamento de outras classes que utilizam desta implementao. Um exemplo tpico seria uma classe que usa um servio de uma outra classe que calcula um determinado imposto. Na evoluo do projeto, muito comum ocorrem mudanas, e uma destas mudanas afetou a forma de como o imposto calculado para uma nica situao especfica. Ao altera este comportamento, voc atenderia a demanda especfica, mas faria com que todas as outras classes que utilizam deste servio deixem de funcionar. Para minimizar estes reflexos no cdigo, devemos reduzir o acoplamento entre as classes usando associaes em vez de herana. Associao entre classes estabelecem uma relao lgica que classificada de duas formas: Agregao ou Composio.

Interfaces
Interface uma ferramenta da orientao a objetos extremamente poderosa. Grande novidade no Delphi 3, Interfaces propem-se a estabelecer uma camada abstrata que determina uma estrutura ou contrato para um objeto. Isto significa que, analogamente a um exemplo real como a de construo de moradias, as necessidades expostas por um processo licitatrio seria nossa interface, ou seja, toda empresa que desejasse participar do processo dever estar em conformidade com as necessidades determinadas no documento de licitao. Com isto temos uma abstrao total de qual empresa objeto efetuar a tarefa.
Ilicitacao = interface procedure DocumentarProjetos; procedure ElicitarRequisitos; procedure ModelacaoUML; end; TEmpresaA = procedure procedure procedure end; TEmpresaB = procedure procedure procedure end; class(TinterfacedObject, Ilicitacao) DocumentarProjetos; ElicitarRequisitos; ModelacaoUML;

class(TinterfacedObject, Ilicitacao) DocumentarProjetos; ElicitarRequisitos; ModelacaoUML;

Neste exemplo, usamos uma interface que declara o mtodo ExecuteCalc, que ser implementado por vrias classes, cada qual a sua necessidade.
type ICalculator = interface function ExecuteCalc(a,b: Double): Double; end; TSum = class(TInterfacedObject, ICalculator)

public function ExecuteCalc(a, b: Double): Double; end; TDivide = class(TInterfacedObject, ICalculator) public function ExecuteCalc(a, b: Double): Double; end; TMultiply = class(TInterfacedObject, ICalculator) public function ExecuteCalc(a, b: Double): Double; end; TSubtraction = class(TInterfacedObject, ICalculator) public function ExecuteCalc(a, b: Double): Double; end; implementation uses SysUtils; function TSum.ExecuteCalc(a, b: Double): Double; begin result := a +b ; end; function TDivide.ExecuteCalc(a, b: Double): Double; begin if b = 0 then begin result := 0; raise Exception.Create('Diviso por Zero !!!!'); end else result := a / b; end; function TMultiply.ExecuteCalc(a, b: Double): Double; begin result := a * b; end; function TSubtraction.ExecuteCalc(a, b: Double): Double; begin result := a - b; end;

Cliente:
var a, b, rSum, rMult: Double; CalcSum, CalcMult: ICalculator; begin

a := 10; b := 20; CalcSum := TSum.Create; rSum := CalcSum.ExecuteCalc(a, b); //resultado da soma rMult := CalcMult.ExecuteCalc(a, b); //resultado da multiplicacao end;

Costumo usar este exemplo com meus alunos, onde eu digo: ...Eu quero um carro. Com esta afirmativa eu coloquei uma necessidade num contexto geral, no me preocupando com os detalhes envolvidos no que eu pedia. Isto uma interface, ou seja, um veculo pra ser entendido como carro precisa de requisitos mnimos, como pneus, motor, volante e como diz minha me: carro pro seu pai basta ter a ignio !. A afirmativa no detalhou qual carro se deseja, isso quer dizer que qualquer objeto concreto (TMercedez) que tenha as caracterstica de um carro (ICarro) solucionaria nossa questo.
type ICarro = interface procedure SetModelo(const Value: string); function GetModelo: string; procedure Ligar; property Modelo: string read GetModelo write SetModelo; end; TMercedez = class(TInterfacedObject, ICarro) private FModelo: string; public procedure SetModelo(const Value: string); function GetModelo: string; constructor Create; published procedure Ligar; property Modelo: string read GetModelo write SetModelo; end; implementation uses Dialogs; constructor TMercedez.Create; begin inherited; FModelo := 'Mercedez'; end; function TMercedez.GetModelo: string; begin result := FModelo; end; procedure TMercedez.Ligar; begin ShowMessage('Motor ligado!'); end;

procedure TMercedez.SetModelo(const Value: string); begin FModelo := Value; end;

Interfaces so componentes indispensveis a uma boa abstrao e reduo de acoplamento. Interfaces no Delphi obedecem a uma hierarquia que tem como base a interface Iinterface. Toda interface escrita em Delphi herda direta ou indiretamente de IInterface, portanto, para uma interface que ter um papel de automao (COM Component Object Model) dever ter IUnknown como interface base. Esta diviso hierrquica atende apenas para fins de organizao, visto que Iunknown explicitamente equivalente a IInterface
IUnknown = IInterface;

Interfaces possuem um mecanismo de contagem de referncia, o que permite o autogerenciamento no que diz respeito aos recursos de memria. Isto elimina a necessidade de liberaes explicitas de objetos atravs de Free, Destroy ou FreeAndNil. {codigo IInterface e mtodos} Interfaces so similares a classes abstratas, que possuem mtodos abstratos no implementados. Uma interface no implementa mtodo algum, ela apenas os declara, os publica, deixando a cargo das classes concretas que os implementam.

Implements
Use a diretiva implements para delegar property da classe a implementao dos mtodos de uma interface.
type IInterfaceA = interface procedure Sample; end; TMyClass = class(TInterfacedObject, IInterfaceA) FMyInterface: IInterfaceA; property MyInterface: IInterfaceA read FMyInterface implements IInterfaceA; end; TConcrete = class(TInterfacedObject, IInterfaceA) public procedure Sample; end; procedure TForm1.Button1Click(Sender: TObject); var MyClass: TMyClass;

InterfaceA: IInterfaceA; begin MyClass := TMyClass.Create; MyClass.FMyInterface := TConcrete.Create; InterfaceA := MyClass; InterfaceA.Sample; end;

Polimorfismo
Polimorfismo o principal recurso que justifica o uso de herana no seu cdigo. Polimorfismo vrias formas uma tcnica que permite o aumento da abstrao na chamada a mtodos de um objeto. Atravs de uma cadeia de heranas, mtodos so herdados da classe progenitora, ocasionando que todas as classes possuam o mesmo mtodo, mas possuam efeitos diferenciados.
TAnimal procedure end;

Walk; //herdar o mtodo Walk

THuman = class(TAnimal) end;

TDog = class(TAnimal) //herdar o mtodo Walk end;

O polimorfismo caracterizado no cdigo quando usamos as diretivas virtual ou dynamic e override nos membros da classe. Isto indica que o mtodo sinalizado como virtual ou dynamic um membro que pertence a uma cadeia polimrfica, ou seja, as classes que herdarem mtodos com estas diretivas podem adicionar novas funcionalidades a eles.
TAnimal procedure end;

Walk;virtual;

THuman = class(TAnimal) procedure Walk;override; end; TDog = class(TAnimal) procedure Walk;override; end;

Uma vez criada esta cadeia polimrfica para o mtodo Walk ganhamos uma maior flexibilidade ao codificar nossas rotinas, uma vez que podemos abstrair o verdadeiro mtodo a ser invocado.
procedure DoWalk(Animal: Tanimal); begin Animal.Walk; end; // begin DoWalk(Tdog.Create); end;

Com isto, em tempo de execuo, o Delphi ir decidir qual mtodo ir invocar, este recurso chamado de ligao tardia ou late binding, pois em tempo de desenvolvimento no possvel se determinar qual instncia ser passada no mtodo DoWalk pode ser qualquer classe que pertena a hierarquia de Tanimal;

Override e Method Hides


A diretiva Override indica um mtodo que sobreposto na classe onde ele declarado. Seu uso freqente na programao orientada a objetos e tem um papel agregador, ou seja, adiciona funcionalidades a um mtodo herdado, uma vez que este tenha sido declarado como virtual ou dynamic. A declarao de um mtodo sobreposto deve seguir fielmente a declarao do mtodo na classe ancestral, fidelidade de nome e lista de parmetros. No entanto, h ocasies em que redeclaramos o mtodo e no o sobrepomos. Isto ocasiona um fato curioso ao compilar a aplicao: [Warning] Unit2.pas(12): Method 'MethodName' hides virtual method of base type 'TMyClass' Este warning do compilador indica que o mtodo virtual MethodName declarado na classe ancestral TMyClass foi ocultado. Isto a indicao que houve uma quebra da cadeia polimrfica para o mthod MethodName, ou seja, o mtodo no poder ser invocado com efeito polimrfico, o mtodo no estar relacionado na VMT. Dica: Na sobreposio de metodos virtuais, na classe corrente, posicionado em uma linha em branco, invoque o code completion ctrl+space e todos os mtodos passveis de sobreposio sero exibidos. Lembre-se a linha dever estar totalmente em branco para que funcione o atalho.
TMyClass = class

//invoque o code completion aqui! end;

Polimorfismo Tcito. Pensando em Cadeia Polimrfica


A cadeia polimrfica estabelecida quando um mtodo no esttico sobreposto seqentemente ou no, nas diversas classes pertencentes a uma hierarquia.
type TFirstClass = class procedure Sample;virtual; end; TSecondClass = class(TFirstClass) procedure Sample;override; end; TThirdClass = class(TSecondClass) procedure Sample;override; end; TFourthClass = class(TThirdClass) procedure Sample;override; end; implementation uses Dialogs; procedure TSecondClass.Sample; begin ShowMessage('Second!'); end; procedure TThirdClass.Sample; begin ShowMessage('Third!'); end; procedure TFourthClass.Sample; begin ShowMessage('Fourth!'); end; procedure TFirstClass.Sample; begin ShowMessage('First!'); end;

A palavra reservada inherited pode ser usada em qualquer situao onde seja necessrio identificar que o mtodo a ser invocado no o da classe atual, mas sim, o da classe ancestral. Mas neste exemplo no foi utilizado para no confundir nosso foco central. No cdigo seguinte, feita uma quebra intencional na classe TFourthClass:
type TFirstClass = class procedure Sample;virtual;

end; TSecondClass = class(TFirstClass) procedure Sample;override; end; TThirdClass = class(TSecondClass) procedure Sample;override; end; TFourthClass = class(TThirdClass) procedure Sample;virtual; end;

O mtodo sample na classe TfourthClass estabeleceu um novo teto polimorfico. E a chamada teria um efeito inusitado:
var FirstClass: TFirstClass; begin FirstClass := TFourthClass.Create; FirstClass.Sample; end; Resultado: Third!

O que aconteceu que o mtodo sample da classe TfirstClass no pertence mais a cadeia, pois foi declarado como virtual e quebrou a seqncia hierrquica. Isto fez com que em tempo de execuo fosse escolhido para execuo o mtodo da classe hierarquicamente acima. Se sample fosse override o mtodo de TfourthClass seria executado.

Virtual ou Dynamic, eis a questo!


As diretivas Virtual e Dynamic so usadas para permitir que o mtodo sinalizado possa ser sobreposto. Um mtodo no esttico (virtual ou dymaic) pode ser reescrito atravs da diretiva override. Ento se ambos permitem a sobreposio, ento qual a real diferena entre eles? Na verdade, mtodos virtuais ou dinmicos atendem ao mesmo problema, a da sobreposio polimrfica, sendo que a diretiva virtual indicada a mtodos que sofrem override com frequncia, pois cria uma entrada na VMT Virtual Method Table, a qual relaciona os endereos de todos os mtodos virtuais de um objeto. Esta abordagem mais eficiente visto que o endereamento da VMT criado em tempo de execuo. Ao criar novas especializaes de uma classe, ela ter sua prpria VMT, relacionando todos os mtodos virtuais herdados e todos os que forem declarados na nova classe. Use a diretiva dynamic para mtodos que no so sobrepostos com frequncia, pois os mesmos so adicionados a Dynamic Method Table, que criada sob demanda.

Sobrecarga de Mtodos
Uma das regras na declarao de classes que no podem haver dois ou mais mtodos com o mesmo nome, ainda que com parmetros diferentes.
type TSample = class procedure Calc(Value: integer); function Calc(a,b: integer): integer; end; implementation uses Dialogs, SysUtils; procedure TSample.Calc(Value: integer); begin ShowMessage(IntToStr(Value)); end; function TSample.Calc(a,b: integer): integer; begin result := a + b; end;

//erro aqui!!

Para permitir essa flexibilidade, utilizada a diretiva overload nos mtodos envolvidos.
type TSample = class procedure Calc(Value: integer); overload; function Calc(a,b: integer):integer; overload; end;

Ao utlizar a classe TSample, os dois mtodos estaro disponveis no code completion.


var Sample: TSample; return: integer; begin Sample := TSample.Create; return := Sample.Calc(1, 2); Sample.Calc(return); end;

O compilador usar os critrios de nmero de parmetros, tipo dos parmetros para determinar qual mtodo dever ser invocado. No caso acima, o fator que determinou o mtodo a ser usado em cada situao foi o nmero de parmetros, uma vez que ambos requerem parmetros de tipos inteiros. O overload tambm pode ser usado em casos de mtodos herdados, para evitar seu ocultamento.
TSample = class procedure Calc(Value: integer);overload; function Calc(a,b: integer): integer;overload; procedure Test;

end; TSample1 = class(TSample) procedure Test(s: string);overload; end;

Com isto, para a classe Tsample1 agora tempos disponvel o mtodo Test herdado da classe ancestral e Test(s: string), novo mtodo sobrecarregado em Tsample1. Na situao a seguir, declarado dois mtodos sobrecarregados, ambos requerem parmetros inteiros, porm de tipos diferentes:
TCalculator = class procedure Calc(si: ShortInt);overload; procedure Calc(si: SmallInt);overload; end;

At aqui nenhum problema que possa nos impedir compilar, mas o que faria o compilador caso eu invoque Calc com o seguinte parmetro:
var Calculator: TCalculator; begin Calculator := TCalculator.Create; Calculator.Calc(29); end;

O compilador ir avaliar o tamanho (range) suportado por cada tipo em ambos parmetros. Shortint Smallint -128..127 signed 8-bit -32768..32767 signed 16-bit

Como o valor passado no parmetro potencialmente poderia ser suportado por ambos os tipos, ser escolhido aquele cujo tipo do parmetro possui o menor intervalo.

Mtodos Abstratos
Mtodos declarados como abstratos usam a diretiva abstract. Este tipo de mtodo no possui implementao na classe onde foi declarado, deixando isto a cargo das classes descendentes. O uso da diretiva abstract sempre vir acompanhada de um virtual ou dynamic, para permitir sobrescrever o mtodo. Classes que especializam classes com mtodos abstratos no so obrigadas a implement-los.
procedure Sample;virtual;abstract;

As classes descendentes podem sobrepor override o mtodo abstrato e implementlo. Ao invocar um mtodo abstrato que no tenha sido sobreposto a seguinte exceo ser erguida:

| Abstract error |

Mtodos abstratos so usados em situaes onde importante que todas as classes de uma cadeia hierrquica tenha um determinado mtodo, como por exemplo um conjunto de classes que modelam o mundo animal, teramos a classe TMamifero com o mtodo abstrato Walk, cuja implementao estaria a cargo das classes descendentes.

Type Casts
Type Cast um mecanismo do Delphi Language que permite a converso pontual de um determinado tipo. Em conjunto com polimorfismo, type casts tornam-se indispensveis na codificao de rotinas genricas. Type Casts so classificados em dois tipos: Value Type Casts e Variable Type Casts. Observe neste exemplo a aplicao de um Variable Type Cast:
TAnimal = class Age: byte; end; TDog = class(TAnimal) Pedigree: string; end; TCat = class(TAnimal) Name: string; end; var Animal: TAnimal; begin Animal := TCat.Create; TCat(Animal).Name := 'Lissi'; end;

//type cast

Observe que foi feita a converso de uma varivel do tipo Tanimal para o tipo Tcat. Isso s foi possivel porque Tanimal ancestral comum a classe TCAt, em outras palavras, elas pertencem a mesma cadeia hierrquica. Value Type Casts so mais incomuns, no aparecem com tanta freqncia. Veja este exemplo:
var ascii: integer; begin

ascii := Integer('Z');

A varivel ascii receber o valor da tabela ASCII correspondente a letra Z. Neste outro exemplo
var obj: TObject; P: Integer; begin Obj := TObject.Create(nil); P := Integer(Obj); //pega o endereo de Obj ShowMessage(TObject(P).ClassName); end;

Encapsulamento
Todo objeto dever ser responsvel por seus prprios comportamentos, com isto garantir a integridade daquilo que o faz funcionar de maneira regular. Encapsulamento uma tcnica OO para ocultar determinados membros de um objeto. Conhecido como Data Hidding o encapsulamento utilizado como mecanismo regulador de acesso aos dados de um objetos. O encapsulamento torna as mudanas no comportamento interno de um objeto transparentes para outros objetos e auxilia na preveno de problemas de efeitos colaterais no cdigo. Pegue o que varia no seu cdigo e encapsule! No necessrio se preocupar em saber como uma tarefa realizada, portanto que seja feita! Quando usamos o mtodo Ligar do objetos carro uma srie de outros mtodos sero invocados internamente no objeto. Estes detalhes do funcionamento no No Delphi existem clusulas que so utilizadas para demarcar regies de uma classe, que determinam qual o grau de visibilidade de cada membro dentro destas regies, so elas Public, Protected, Private, Published, Strict Private, Strict Protected. Pblico A propriedade ou mtodo da classe pode ser acessado por todas as demais entidades do sistema. Privado O acesso aos membros da classe s permitido aos mtodos da prpria classe. Protegido O acesso aos membros da classe s permitido a classes da mesma hierarquia. Published

Regras de visibilidade idnticas ao public, sendo que alm disso; aparece no object inspector (no caso de componentes do delphi ). Um dos questionamentos que caberiam seria: O que encapsular? Quando encapsular? Pra que encapsular? Evidentemente todas estas perguntas precisam e devem ser respondidas e esclarecidas. A linguagem Delphi fornece um recurso muito utilizado quando trabalhamos com encapsulamento, as Propertys, assim com os campos de uma classe, as propriedades criam um mecanismo de leitura e escrita para um campo privado classe. Muito mais eficiente que a declarao simples de um campo, propriedades permitem uma forma concreta de controle do que pode ser escrito e lido de um determinado campo. Quem nunca teve um erro em sua frente Invalid property value quando entrou com um valor incompatvel a uma propriedade ainda que acidentalmente atravs do object inspector. Propriedades so declaradas geralmente nas sees public ou published de uma classe e obedece a seguinte semntica:
property NoDaPropriedade: Tipo read FNoDaPropriedade write FnoDaPropriedade;

Get e Sets
Uma vez que as propriedades promovem uma forma de encapsulamento e controle de leitura e escrita, podemos substituir a leitura e escrita direto do campo por mtodos Get e Set.
Property Nome: string read GetNome write SetNome;

Os mtodos GetNome e SetNome sero usados pela property para as tarefas de leitura e escrita na varivel encapsulada. Isto nos permite criar um estgio de verificao preliminar a escrita ou leitura do campo.

O Operador Index
Os mtodos Get e Set so instrumentos eficientes no controle da leitura e escrita por parte de uma propriedade, mas pode ser tornar um elemento perturbador no que diz respeito a legibilidade de uma classe, por isso, possvel compartilhar um nico par de mtodos Get e Set entre diversas propriedades indexadas. Para declarar esta funcionalidade adicione a diretiva index seguido de um inteiro entre -2147483647 e 2147483647 em todas as propriedades que iro usar os mtodos compartilhados:
type TAluno = class private

FNome: string; FEmail: string; FTelefone: string; function GetData(const Index: Integer): string; procedure SetData(const Index: Integer; const Value: string); public property Nome: string index 0 read GetData write SetData; property Email: string index 1 read GetData write SetData; property Telefone: string index 2 read GetData write SetData; end; implementation function TAluno.GetData(const Index: Integer): string; begin case Index of 0: result := FNome; 1: result := FEmail; 2: result := FTelefone; end; end; procedure TAluno.SetData(const Index: Integer; const Value: string); begin case Index of 0: FNome := Value; 1: FEmail := Value; 2: FTelefone := Value; end; end;

Dica: Na declarao de propriedades, digite a penas at o tipo, encerrando em seguida com ponto e virgula. Logo aps pressione ctrl+shift+c e o restante da estrutura da propriedade ser criada automaticamente.

Propriedades Indexadas
Propriedades podem ser declaradas de forma a permitir a leitura seqencial de uma estrutura ordinal como um array. A declarao bem simples, basta informa a lista de parmetros ao lado do nome da propriedade:
interface uses Classes; type TCliente = class private FTelsList: TStringList; function GetTelefones(Index: integer): string; procedure SetTelefones(Index: integer; const Value: string); public constructor Create; destructor Destroy; override;

property Telefones[Index: integer]: string read GetTelefones write SetTelefones; end; implementation uses SysUtils; constructor TCliente.Create; begin inherited; FTelsList := TStringList.Create; end; destructor TCliente.Destroy; begin FreeAndNil(FTelsList); inherited; end; function TCliente.GetTelefones(Index: integer): string; begin result := FTelsList.Strings[Index]; end; procedure TCliente.SetTelefones(Index: integer; const Value: string); begin FTelsList.Strings[Index] := Value; end;

Para Ter acesso a leitura e escrita na propriedade Telefones informe o indice desejado:
var Cliente: TCliente; begin Cliente := TCliente.Create; Cliente.Telefones[0] := '21 2223-1234'; end;

También podría gustarte