Você está na página 1de 20

Descrio

Este artigo tem como finalidade explanar a Programao Orientada a Objetos de uma maneira clara e
superficial queles que ainda no a conhecem. Procura ilustrar apenas alguns dos principais conceitos da POO,
mas de maneira prtica e interessante, sem sobrecarregar os leitores, de modo que se possa preparar o
terreno para outras explicaes que envolvem a Orientao a Objetos venham em prximas publicaes.
Pr-requisitos
Habilidade em programao com delphi em qualquer verso, conhecimento de Object Pascal e, principalmente,
cabea aberta.
O que a Orientao a Objetos
Quantas vezes folheamos livros ou artigos de programao que falavam dessa tal "Programao Orientada a
Objetos, sem que entendssemos sequer uma linha do que estava escrito? Muitas vezes. O que acontece
que esse par de letras "O que tanto nos assusta, fica mais feio ainda depois de acompanhado de tantos
palavres, como "polimorfismo, "herana mltipla, "agregao e outras greguices que insistem tanto em
participar destes artigos.
Orientao a Objetos o simptico nome que os pesquisadores da computao na dcada de 70 usaram para
batizar este novo "paradigma, que tinham acabado de inventar. E no para menos, pois veremos que neste
estilo de programao - como queriam os seus criadores - tudo objeto. Ou ao mnimo, se pretende que seja.
Ainda como era nossa inteno falar, a Orientao a Objetos um novo paradigma, que procura re-arranjar a
programao estruturada de uma maneira diferente, e talvez bem mais compreensiva ao raciocnio do homem.
Ela pretende descrever a soluo atravs de objetos - como no mundo real - ao contrrio da programao
estruturada, que o faz atravs de passos e comandos, de maneira semelhante a uma receita de bolo.
Um paradigma, caso o leitor no saiba, uma maneira diferente de se tentar enxergar uma mesma coisa, um
mesmo mundo. O Paradigma OO busca bases filosficas para tentar traduzir um mundo mais humano s
instrues que o processador realmente entende. E de viagens deste tipo, combinadas estrutura de
linguagens imperativas como o C ou Pascal, que surgem as linguagens OO. E estas ltimas se responsabilizam
pela existncia da maioria dos grandes softwares produzidos nos dias atuais em todo o mundo.
Mas por que diabos isso foi inventado?
Desde que surgiu, a computao tem evoludo de uma maneira bastante rpida. Esta evoluo acabou levando
a comunidade deste meio a se deparar com a chamada "crise do software. A orientao a objetos surgiu nos
primrdios da dcada de 70, com as linguagens ADA, SIMULA e Small Talk. Ela ficou bastante difundida nos
anos 80, com linguagens como o C++, e teve uma recente exploso em difuso nos anos 90, atravs da
linguagem Java. Hoje em dia muito comum encontrarmos compiladores e tradutores para linguagens OO, tais
como Object Pascal, C++, Java e Visual Object.
A "crise do software acabou levando os desenvolvedores da poca a buscar uma soluo alternativa, pois a
complexidade dos sistemas j havia chegado a tal ponto que nem os seus programadores conseguiam domin-
la mais. Sabia-se que as linguagens estruturadas no davam mais suporte s necessidades, e esta
possivelmente tenha sido a principal causa do surgimento das linguagens OO.
Tambm no para menos. Se voc tentar olhar um programa como o AutoCAD com os olhos de programador,
ir entender o que queremos dizer com a palavra "complexidade. Para um programador experiente em OO,
fica difcil sequer imaginar uma soluo destas sem que se modele um mundo de objetos. Da a nossa inteno
em dizer que a POO surgiu para suprir a crise do software - e conseguir dividir os sistemas de maior
complexidade em partes independentes e que possam, assim, se manter sob o controle de seus criadores.
Afinal de contas, o que um Objeto?
Os livros e artigos de OO costumam dizer que um objeto qualquer coisa. No que eles no tenham razo
nesta frase, mas talvez no tenham muita clareza. Isto porque a resposta para essa pergunta deveria ser a
mesma que voc diria, se lhe perguntassem "O que um objeto para voc?. Aps responder a esta pergunta,
basta tentar imaginar que voc ir representar o mundo no seu programa, atravs de objetos, e o significado
comea a brotar na cabea. Um objeto, para voc, o que ? Um lpis? Um tijolo? Um copo? Exatamente.
Por definio, um objeto pode ser entendido como alguma coisa que existe, que possui caractersticas, e que
faz algo. Este conceito ideal para explicarmos o que um objeto dentro do programa, em termos da
linguagem. Um objeto, numa linguagem OO, um indivduo que possui atributos (estado) e mtodos
(comportamento), tal qual o mesmo objeto visto no mundo real. Os atributos, conforme veremos,
representaro dados e os mtodos, trechos de cdigo executvel.
Se voc j chegou at aqui, e mesmo assim no conseguiu entender completamente o que objeto, no se
preocupe. Provavelmente as coisas devero clarear quando comearmos a ver isso na prtica. E esta, conforme
esperamos, dever ser a melhor parte. Mas por enquanto, precisaremos apenas abordar mais algumas
"coisinhas, para que se possa colocar a mo na massa com um mnimo de confiana.
lasses e !nst"ncias
Para entender melhor os princpios da OO - por mais chato ou viajante que isto seja - necessrio abordar
dois elementos essenciais: classe e instncia. Estes elementos, que parecem estar mais ligados filosofia do
que prpria programao, so de fundamental compreenso aqui, mesmo com a mais simples das
explicaes. Portanto, caro leitor, nem pense em pular esta parte, ou ento voc ser condenado a no
entender praticamente nada mais frente.
Podemos dizer que classes so o conjunto de todos os elementos semelhantes, no nosso caso, objetos. Todo
objeto pertence a uma determinada classe, assim na terra como no cu, isto , assim no mundo real quando no
"mundo descrito no programa. Classes so tipos de coisas, e descrevem as coisas de uma maneira generalista,
atravs de regras a que todos os elementos que a ela pertencem devem seguir, sem que necessariamente se
conhea uma ou outra dessas "coisas.
Assim existe, por exemplo, a classe dos livros, a que pertencem todos os livros publicados. classe dos
equipamentos eletrnicos pertencem todos os computadores, televisores e outros dispositivos, bem como
classe dos humanos se espera que pertenam todas as pessoas.
Em contrapartida, citamos a instncia, que significa um elemento especfico daquela classe. Uma instncia um
constituinte singular e conhecido da populao daquela classe. A instncia, ao contrrio da classe, procura
referir um elemento conhecido da sua classe.
Assim como voc uma instncia da classe dos humanos, tal qual este monitor sua frente uma instncia da
classe de equipamentos eletrnicos, ou ainda aquele livro de Biologia de Soares disposto ao lado de sua
cabeceira uma instncia da classe dos livros. Instncias so, portanto, casos de ocorrncia das classes.
Agora tratando novamente de classes, porm em termos de programao, diremos que elas so tipos
declarveis. No Delphi, a declarao de uma classe, feita atravs da palavra reservada class, como segue
abaixo:
unit Unit1;
type
TAnimal = class
end;
Logo, TAnimal representar a classe dos animais, e nela sero definidas as caractersticas (regras) a que todo e
qualquer animal dever seguir. Vale lembrar que, por padro no Delphi, convenciona-se os tipos como
identificadores comeados com a letra T.
Entretanto, embora tenhamos acabado de criar a classe dos animais, ainda no existe nenhum animal no nosso
sistema. Isto porque no existe nenhuma referncia a um animal, muito embora o compilador j "saiba da
possvel existncia dos animais. Para que possamos referenciar uma instncia de animal, declararemos uma
varivel do tipo TAnimal:
var
MeuAnimal: TAnimal;
Isto, teoricamente, resolve o nosso problema. At porque agora j temos uma referncia a um animal, apesar
de no o conhecermos. Mais adiante veremos que isso no exatamente verdade, mas vamos considerar que
ele existe, por enquanto. Agora voc sabe que possui um animal, e que se referiu a ele como MeuAnimal.
Atributos
Bom, voc j declarou sua primeira classe. Mas o que ela faz? Para que ela serve? Absolutamente nada, por
enquanto. Como sugerimos antes, um objeto uma entidade que deve possuir estado e comportamento. E
para dar esta vida aos objetos que lhes caracterizamos com atributos e mtodos. E nesta seo vamos explicar
como dar estado ao objeto, ou seja, dar-lhe a capacidade de guardar informaes.
Voltando ao nosso primeiro exemplo, iremos aperfeioar melhor a descrio do nosso animal, dando-lhe duas
caractersticas, altura e peso. Tambm vamos personaliz-lo, dando-lhe a possibilidade de ter um nome. O
nosso exemplo ficar assim:
unit Unit1;
type
TAnimal = class
Nome: string;
Altura, Peso: real;
end;
Bom, a partir de agora o seu objeto j possui a capacidade de guardar informaes dentro dele. Poderamos dar
um nome, uma altura e um peso a MeuAnimal, acessando os seus dados internos (atributos) como no exemplo
abaixo:
implementation
procedure TForm1.Button1Click(Sender: TObject);
begin
MeuAnimal.Nome := 'Cachorro Pluto';
MeuAnimal.Altura := 0.72;
MeuAnimal.Peso := 9.3;
end;
Entretanto, se voc compilar o seu projeto, e mandar que ele execute este cdigo, ele no dever funcionar,
levantando um erro de violao de acesso. Mas porque? Simples e bvio. Voc realmente ordenou ao sistema
que ele atribusse o nome, peso e a altura ao MeuAnimal, mas voc esqueceu de dizer quem era ele. Em outras
palavras, a sua referncia MeuAnimal est apontando para ningum. Em termos do Delphi, digamos que ela
nula, ou seja, possui valor nil.
Mas ento para quem eu devo faz-la apontar? Eis a questo. Acontece que no existe nenhum animal no seu
sistema. Se voc voltar alguns pargrafos deste texto, onde ainda falvamos do que vem a ser um objeto, se
lembrar que um fundamento bsico e filosfico do objeto existir. E para que alguma coisa passe a existir, ela
primeiro deve ser criada. E assim como no mundo real, atravs de chamadas especficas, faremos objetos
serem construdos e destrudos.
onstrutores e Destruidores
Construtores e destruidores so mtodos especiais - mais abaixo explicaremos melhor o que so mtodos -
responsveis pela criao e destruio de objetos. Os especialistas em linguagens orientadas a objeto
costumam dizer que eles so mtodos de classe. Mas isso no vem muito ao caso aqui.
O que importa que em algum momento do nosso exemplo, um animal precisa ser criado, at para que possa
receber aqueles valores que tentamos lhe atribuir mais acima. E justamente esse o papel que tem um
construtor. O construtor de uma determinada classe seria um mtodo ou procedimento capaz de criar, ou
instanciar, um objeto pertencente quela classe. Sendo assim, para que construamos o nosso animal,
usaremos a seguinte linha de cdigo:
MeuAnimal := TAnimal.Create;
Esta chamada ir invocar o construtor padro da classe, derivado da classe ancestral de todas, a classe
TObject. Mas no se preocupe com isso agora. O importante que, a partir da execuo desta linha de cdigo,
passa a existir uma instncia de TAnimal no seu programa, com memria alocada para ela, e MeuAnimal agora
aponta para esta instncia. To logo, para que aquele nosso cdigo que resultou em erro funcione, vamos
refaz-la da seguinte maneira:
procedure TForm1.Button1Click(Sender: TObject);
begin
MeuAnimal := TAnimal.Create;
MeuAnimal.Nome := 'Cachorro Pluto';
MeuAnimal.Altura := 0.72;
MeuAnimal.Peso := 9.3;
end;
Uma vez feito isto, e depois de executado este bloco de cdigo, MeuAnimal passa a existir na memria, e a
armazenar os dados que ora inserimos nele. Se no acreditar, ou se quiser ter certeza disto, execute o bloco
de cdigo seguinte:
procedure TForm1.Button2Click(Sender: TObject);
begin
ShowMessage('Meu nome ' + MeuAnimal.Nome);
ShowMessage('Minha altura ' + FloatToStr(MeuAnimal.Altura) + ' cm');
ShowMessage('Meu peso ' + FloatToStr(MeuAnimal.Peso) + ' kg');
end;
Agora que j sabemos o que um construtor, passemos para o destruidor (ou destrutor, no vcio da traduo).
Um destruidor, como sugerido antes, capaz de destruir o objeto em questo, liberando a memria que foi
alocada para ele. MeuAnimal, portanto, deixa de existir a partir do momento que executamos esta linha de
cdigo:
procedure TForm1.Button3Click(Sender: TObject);
begin
MeuAnimal.Destroy;
end;
A rea de memria reservada para aquele TAnimal foi liberada. Entretanto, importante ressaltar que isto no
limpa a referncia MeuAnimal, que continua apontando para a regio de memria onde estava o TAnimal. Esta
inconsistncia pode trazer conseqncias desagradveis para o sistema. Portanto, para um cdigo seguro,
sempre informe s referncias que elas no mais apontam para ningum, imediatamente aps destruir os
objetos:
procedure TForm1.Button3Click(Sender: TObject);
begin
MeuAnimal.Destroy;
MeuAnimal := nil;
end;
Mtodos
Conforme dissemos j algumas vezes, um mtodo um bloco de cdigo executvel, capaz de definir
comportamento ao objeto. Ao grosso modo, um mtodo pode ser entendido como um procedimento
(procedure) ou funo (function), porm com a diferena de que ele se limita - ou ao menos deve se limitar -
ao escopo do objeto a qual ele pertence. Mtodos, de uma maneira geral, esto vinculados s instncias.
No fugindo muito da prtica, e como se era de esperar, voltemos ao nosso velho exemplo do animal. J lhe
demos a capacidade de possuir estado, guardando algumas informaes. Agora lhe daremos a possibilidade de
se comportar, ou seja, literalmente o animaremos. Acrescentaremos em TAnimal trs mtodos: Correr, Crescer
e Encolher. Estes mtodos lhe daro a possibilidade de mudar seu estado. Vejamos como fica a nossa
declarao:
unit Unit1;
type
TAnimal = class
Nome: string;
Altura, Peso: real;
procedure Correr;
procedure Crescer(const incremento: real);
procedure Encolher(const decremento: real);
end;
var
MeuAnimal: TAnimal;
implementation
procedure TAnimal.Crescer(const incremento: real);
begin
Altura := Altura + incremento;
ShowMessage('Minha nova altura ' + Altura);
end;
procedure TAnimal.Encolher(const decremento: real);
begin
Altura := Altura - incremento;
ShowMessage('Minha nova altura ' + Altura);
end;
procedure TAnimal.Correr;
var i: Integer;
begin
ShowMessage('Eu, ' + Nome + ', estou correndo!');
for i := 1 to 5 do
begin
ShowMessage('Estou no meu passo de nmero ' + IntToStr(i));
end;
ShowMessage('Eu, ' + Nome + ', cansei de correr.');
end;
E invocaremos os mtodos conforme abaixo:
procedure TForm1.Button4Click(Sender: TObject);
Begin
MeuAnimal.Crescer(0.1);
MeuAnimal.Encolher(0.5);
MeuAnimal.Crescer(0.3);
MeuAnimal.Encolher(0.2);
end;
procedure TForm1.Button5Click(Sender: TObject);
begin
MeuAnimal.Correr;
end;
Se o leitor pde perceber, os mtodos da classe TAnimal manipulam diretamente os atributos, fazendo com que
o objeto dono do mtodo invocado - ele e somente ele - seja manipulado. E exatamente essa a proposta de
definio de comportamento dos objetos, manipular dados dentro de seu escopo.
Muitos outros mtodos so e devem ser desenvolvidos, de maneira a descrever, da maneira mais adequada
possvel, o comportamento desejado do objeto diante do sistema. Entretanto, veremos mais adiante, numa
prxima publicao, onde abordaremos outros conceitos da OO.
onsidera#es $inais
Este artigo, como h de se perceber, est longe de estar completo. Muitos dos conceitos fundamentais da OO
no foram tratados aqui, e o projeto, tal qual o desenvolvimento de sistemas orientados a objeto, requerem
mais conceitos que no couberam aqui. Pretendemos que mais trs partes deste mesmo texto sejam
publicadas, de maneira contnua. Esta apenas a primeira, e a mais introdutria delas.
O artigo no pretendeu, de maneira nenhuma, ser fonte bibliogrfica sobre orientao a objetos. O seu objetivo
foi, acima de tudo, trazer luz da realidade os conceitos da OO, esta que sofre uma certa resistncia por parte
dos programadores, principalmente dos menos experientes, acabando por ser isolada, graas ao preconceito.
Outras abordagens estaro disponveis nos nossos prximos artigos, de modo que possamos dar uma viso
geral e clara sobre outros conceitos importantes da OO. Procuraremos, na medida do possvel, e de maneira
semelhante, trazer prticas do que for mostrado. Tentaremos desmistificar a OO, para que cada vez mais
possamos perder o medo deste paradigma de programao que, quando bem usado, pode fazer coisas
fantsticas.
!ntroduo
Uma vez cumpridos os pr-requisitos dispostos logo acima, pressupe-se agora que o leitor j saiba o que um
objeto, o que uma classe e uma instncia, o que so atributos, e o que so mtodos. Pressupe-se, ainda,
que j saiba construir e destruir objetos. Logo, podemos dar continuidade nossa superficial abordagem sobre
OO.
Conforme j foi dito na publicao anterior, ainda existem muitos conceitos fundamentais a serem vistos sobre
Orientao a Objetos - conceitos estes que, aplicados, tornam a programao bastante poderosa, quando
comparado ao paradigma anterior. Muito ainda se h por falar sobre este estilo que virou a programao dos
anos 60 de cabea para baixo. Portanto se voc, caro leitor, acha que porque leu o artigo anterior j sabe fazer
programas orientados a objeto, saiba que est redondamente enganado.
Nesta seo abordaremos de maneira prtica, um dos trs princpios que tornam uma linguagem de fato
Orientada a Objetos: herana, polimorfismo e encapsulamento. Falaremos da herana.
%enerali&ao e 'speciali&ao
Voltemos a tratar de um objeto novamente como um elemento do mundo. Ele definido por uma determinada
classe, e uma vez construdo, toma a sua forma concreta, isto , passa a existir como instncia desta classe.
Logo, este objeto um elemento pertencente a esta classe. No exemplo anterior, definimos uma classe de
animais chamada TAnimal, contendo alguns atributos e mtodos, e estabelecemos uma instncia desta classe,
a qual nos referimos por MeuAnimal.
Entretanto, surge que classes nicas e separadas entre si, como supomos antes, no so suficientes para
definir todo um universo e as coisas que nele existem. Isto acontece principalmente porque alguns objetos
podem pertencer a mais de uma classe ao mesmo tempo. Na verdade, quase todos eles provavelmente
pertencem.
Podemos dizer que um determinado livro uma instncia da classe dos livros, enquanto o mesmo livro tambm
pertence classe dos materiais escolares. E por que no? Neste caso, surge uma questo bastante comum no
nosso cotidiano, no que diz respeito classificao das coisas. Eis que a questo : algumas classes so
subconjuntos de outras. A classe dos livros pode ser vista como um subconjunto especial da classe dos
materiais escolares. Em palavras mais srias, diramos que os materiais escolares generalizam os livros. Os
livros, por sua vez, seriam uma especializao dos materiais escolares, se olharmos pelo sentido contrrio.
Se pararmos para observar, existem muitas outras situaes no nosso cotidiano envolvendo este assunto. As
pessoas, por exemplo, so uma classe especial de mamferos, estes que por sua vez so uma subclasse de
animais, enquanto estes ltimos so generalizados por seres vivos. Se o leitor olhar ao prprio redor, ir
encontrar muitos outros casos bem parecidos.
E como resolver a esta questo? Eis que surge a herana, que um recurso voltado a resolver este tipo de
problema, trazendo ainda consigo uma srie de outras vantagens que vm a otimizar o desenvolvimento de
solues em cdigo executvel. Falaremos sobre ela a seguir.
(erana
Nada de muito extraordinrio ao nosso entendimento ser tratado aqui, uma vez que j temos alguma noo
de generalizao e especializao. Extraordinrio com certeza o poder que este recurso tem. A herana vem a
ser a forma usada pelas linguagens OO para implementar a especializao. Uma determinada classe que
especialize outra, diremos que ela herda desta. Assim dizemos que a classe herdada a ancestral, e a herdeira
a descendente. Vejamos o exemplo abaixo, adaptado do nosso exemplo do artigo anterior:
unit Unit1;
type
TSerVivo = class
end;
TAnimal = class(TSerVivo)
end;
TVegetal = class(TSerVivo)
end;
A partir deste par de parnteses depois da declarao da classe TAnimal, fizemos esta classe herdar de
TSerVivo. Em outras palavras, nosso sistema agora entende que todo animal tambm um ser vivo, e o
especializa. O mesmo se aplica a TVegetal. E assim que o nosso programa enxergar estes objetos: as
instncias de TAnimal e de TVegetal agora sero, todas ao mesmo tempo, tambm pertencentes classe
TSerVivo, devendo ser tratadas como tal. Uma classe pode ter inmeras classes descendentes diferentes.
E a classe TSerVivo, herda de quem? De ningum? Excelente pergunta. E bem oportuna. Quando voc no
declara uma ancestral sua classe, o delphi automaticamente o faz descendente da classe mais ancestral de
todas, a classe TObject.
Agora vamos complicar um pouquinho mais o nosso modelo:
unit Unit1;
type
TSerVivo = class
Alimento: string;
Peso: Real;
end;
TAnimal = class(TSerVivo)
Membros: Integer;
Velocidade: Real;
end;
TVegetal = class(TSerVivo)
Fruto: string;
end;
Agora alm de uma relao de herana entre as classes TSerVivo e as descendentes TAnimal e TVegetal,
demos atributos a cada uma delas. Todo TAnimal agora possui uma velocidade de locomoo, representado
pelo atributo Velocidade, bem como um nmero de membros. Os vegetais por sua vez tero o nome do fruto
que produzem. De igual forma, demos a todo TSerVivo o direito de escolha por um alimento preferido,
representado pelo campo Alimento e uma informao de peso, pelo campo Peso.
Agora chegamos num ponto interessante. Dada as seguintes referncias:
var
MeuSerVivo: TSerVivo;
MeuAnimal: TAnimal;
Poderemos facilmente atribuir um nmero qualquer de membros a MeuAnimal, desde que ele esteja
instanciado. De igual maneira, podemos informar a MeuSerVivo que ele gosta de comer 'frutas tropicais',
simplesmente atribuindo-lhe o valor ao respectivo atributo. Mas podemos atribuir um peso a MeuAnimal? A
resposta uma outra pergunta: Por que no?
Como poderia se imaginar, todo animal tambm um ser vivo e, como ser vivo, ele tambm respeita s
caractersticas e regras estabelecidas para todos os seres vivos. Em outras palavras, TAnimal literalmente
herda os atributos de TSerVivo, podendo ser to manipulvel nisto enquanto TAnimal, como qualquer instancia
de TSerVivo. E isto se aplica tanto aos atributos quanto aos mtodos.
No existe um limite mximo para quantos nveis de especializao se pode haver entre classes. Uma classe
ancestral, tal como TObject, pode ter milhares de descendentes em cascata, e isto o torna os sistemas OO
dotados de um amplo poder de classificao. Agora vamos incrementar nosso modelo um pouco mais:
unit Unit1;
type
TSerVivo = class
Alimento: string;
Peso: Real;
procedure AlimentarSe(const Alimento: string);
end;
TAnimal = class(TSerVivo)
Membros: Integer;
Velocidade: Real;
procedure LocomoverSe(const Direcao: string);
end;
TVegetal = class(TSerVivo)
Fruto: string;
procedure ProduzirOxigenio;
end;
var
MeuSerVivo: TSerVivo;
MeuAnimal: TAnimal;
MeuVegetal: TVegetal;
implementation
procedure TSerVivo.AlimentarSe(const Alimento: string);
begin
if Self.Alimento <> Alimento then
ShowMessage('Estou comendo ' + Alimento + ', mas eu gostaria e estar' +
'comendo ' + AlimentoPreferido)
else
ShowMessage('Estou comendo ' + Alimento + ', que o que eu Gosto');
Peso := Peso + 1;
end;
procedure TAnimal.LocomoverSe(const Direcao: string);
var i: Integer;
begin
for i := 1 to Membros do
begin
ShowMessage('Estou movendo meu membro No.' + i + ' para ir a ' + Direcao);
end;
ShowMessage('Estou a ' + FloatToStr(Velocidade) + ' Km/h');
end;
procedure TVegetal.ProduzirOxigenio;
begin
ShowMessage('Estou contribuindo para a atmosfera do nosso planeta.');
end;
end.
Ora, sabe-se que apenas os vegetais produzem oxignio, e por isso declaramos o mtodo ProduzirOxigenio
apenas em TVegetal. Mas sabe-se que tanto os animais quanto os vegetais se alimentam, e por isso tivemos o
cuidado de declarar o mtodo AlimentarSe na classe imediatamente superior.
Voc perceber que poder invocar o mtodo AlimentarSe tambm de MeuAnimal, e de MeuVegetal uma vez
que ele tambm uma instncia de TSerVivo. Entretanto, vale notar que os elementos membros de TAnimal
no so acessveis por instancias de TSerVivo, j que seres vivos no so necessariamente animais.
Mas observa-se que a herana possui um grande papel tanto na questo de modelar classes relacionadas
quanto na economia de trabalho dos programadores. Se considerarmos uma classe B qualquer herdado de uma
classe A, teremos que B trar automaticamente para si todas as caractersticas (atributos e mtodos) de A, no
precisando assim reescrev-las.
Declarando ), !nstanciando *
Como vimos logo acima, um objeto pode ser instncia de uma classe que descendente de uma outra mais
ancestral. E este objeto pode ser tratado como uma instncia desta ltima classe mais genrica. Logo, o critrio
de generalizao disposto pela herana nos permite uma boa flexibilidade quanto s referncias. Vejamos:
var
MeuSerVivo: TSerVivo;
implementation
procedure TForm1.Button6Click(Sender: TObject);
begin
MeuSerVivo := TAnimal.Create;
end;
Pode-se ver, o exemplo acima declara uma referncia a um TSerVivo, e a contraria, instanciando para ela um
objeto do tipo TAnimal. Isto permitido? Sim, claro. Como j demonstramos, todo TAnimal tambm um
TSerVivo, herda todas as suas caractersticas, e no existe nenhuma razo lgica que proba isso. Apenas a
situao contrria no seria permitida, j que nem todo ser vivo se trata de um animal.
O nico inconveniente que isso provoca o fato de que, uma vez a referncia sendo do tipo da classe superior,
no h como saber de imediato que a instncia apontada da classe inferior. Logo, os atributos e mtodos
exclusivos de TAnimal no estaro disponveis em MeuSerVivo em tempo de compilao. Verifique isso
digitando MeuSerVivo. [control + espao], e voc perceber que os nicos atributos e mtodos disponveis so
os declarados at a classe TSerVivo.
Mas isso no quer dizer que voc no tenha como acess-los por causa disso. Uma vez que voc tem certeza
que a instncia apontada pela referncia MeuSerVivo do tipo TAnimal, voc pode informar ao compilador que
se trata de uma instncia de TAnimal, fazendo o chamado typecasting para esta classe, e assim resgatar
novamente os atributos e mtodos de TAnimal. Para isso, usa-se o operador as:
procedure TForm1.Button6Click(Sender: TObject);
begin
MeuSerVivo := TAnimal.Create;
(MeuSerVivo as TAnimal).LocomoverSe('Leste');
end;
Feito isso, o compilador passa a "entender que o objeto apontado por MeuSerVivo do tipo TAnimal, confiando
na palavra de honra do programador, e liberando assim os seus atributos e mtodos para uso. Nota: ao fazer
typecasting, certifique-se de que realmente o objeto apontado seja da instncia declarada com o as, ou isto
poder resultar numa exceo em tempo de execuo.
(erana M+ltipla
Bom, agora vamos fugir um pouco ao assunto para tratar deste outro um pouco mais controverso. Herana
Mltipla um conceito um pouco mais complicado de herana nas linguagens OO, e bastante questionado entre
os estudiosos da rea. Sabe-se que a herana mltipla implementada em certos pontos no Ansi C++, no
posso garantir em todos.
A herana mltipla visa permitir que uma classe possa herdar caractersticas de mais de uma classe ancestral
ao mesmo tempo, fazendo, por exemplo, que um carro-anfbio possa herdar das classes Carro e Barco ao
mesmo tempo. Trata-se de um recurso bastante poderoso em termos de linguagem. Mas igualmente
perigoso, e possivelmente complicado no desenvolvimento do seu compilador.
O Delphi, como muitas das linguagens OO comerciais e amadurecidas, no implementa a herana mltipla. Por
isso no entraremos em mais detalhes sobre esse assunto aqui. Mas o Delphi, bem como o Java, usam de
recursos que podem simular a herana mltipla em determinados aspectos que so benficos - especialmente
os relacionados tipagem (classificao) e abstrao - e ao mesmo tempo isolar outros que podem ser
perigosos e complicados - como a herana de atributos. A este "recurso usado pelo Delphi e pelo Java, damos
o nome de interface. Ainda no veremos isto nesta publicao, ficando para as posteriores.
lasses oncretas e Abstratas
Bom, em meio s dezenas - s vezes centenas - de classes existentes num modelo, notaremos que algumas
dessas classes podero ser instanciadas, outras no. Isto se deve ao fato de que, muito embora dois objetos
que pertenam a uma classe mais ancestral possuam caractersticas comuns, acontece de no haver como
existir um elemento que represente, de forma fsica e real, aquela classe em questo.
Voltamos ao nosso exemplo de TAnimal e TSerVivo. Muito embora nada no Delphi nos impea de instanciar um
TSerVivo na sua pura essncia, isso no faz o menor sentido. Voc j viu algum ser vivo que no seja instncia
de uma classe mais inferior?
A casos como este, em que no existe nenhuma razo para a construo de objetos especificamente de uma
classe, chamamos esta classe de classe abstrata. Ao caso contrrio, isto , de classes instanciveis, chamamos
de classes concretas. Classes abstratas geralmente so ancestrais de outras classes concretas. A recproca
verdadeira.
Infelizmente no caso do nosso exemplo s tratamos de classes abstratas - claro que vamos desconsiderar o
construtor Create invocado no exemplo artigo anterior. Mas em termos conceituais, no faz sentido se
instanciar um TAnimal. Se algum lhe perguntasse "qual o seu bicho de estimao?, e voc respondesse " um
animal, a pessoa voltaria a perguntar "Qual animal?, no melhor dos casos. No pior, lhe chamaria de louco.
Ento resolvamos o problema do seu bicho de estimao da seguinte maneira:
type
TCachorro = class(TAnimal)
Dono: string;
procedure Latir;
end;
Agora sim, poderemos citar uma classe concreta! At porque existem cachorros de verdade no nosso mundo,
sob a forma real de cachorro. Animais tambm existem, porm, sob forma de cachorros, gatos, etc. Nunca
como animal apenas.
Por vias formais, definimos como uma classe abstrata, aquela que possui mtodos abstratos. Mtodos abstratos
so aqueles que no possuem implementao fsica na classe. No Delphi eles so declarados por uma diretiva
abstract depois da sua assinatura. Veremos isto mais adiante, numa prxima publicao. Ao contrrio do
Delphi, algumas linguagens como Java no permitem a instanciao de classes abstratas.
Se voc instanciar uma classe abstrata no delphi, como TStrings por exemplo, ele permitir, embora lhe d um
aviso em compilao "constructing instance of abstract class. O erro s ocorrer em tempo de execuo,
quando voc invocar um mtodo abstrato. Da, para evitar o problema, sempre instancie classes concretas,
nunca abstratas. Uma boa candidata a ser construda de maneira correta neste caso a classe TStringList,
descendente de TStrings.
Este tipo de permissividade do Delphi, de instanciar classes abstratas, leva ao questionamento de alguns
pesquisadores, tanto em termos de consistncia do projeto quanto da compreenso do modelo especificado.
Java, nesse aspecto, parece ser mais fiel ao paradigma OO, por no permitir a compilao.
onstrutores e Destruidores espec,ficos
Suponha agora que aquele seu cachorro - aquele declarado na seo anterior - tenha um dono. Logo, nada nos
custa dar um atributo Dono ao pobre animal. Suponha ainda que na regra do nosso projeto no possam existir
cachorros sem dono, em nenhum momento, e nem se pode correr esse risco.
Se voc considerar que usar o construtor padro, derivado de TObject (aquele Create sem parmetros),
dever admitir que o desenvolvedor que usar sua classe poder esquecer de dar um dono ao cachorro. Isto, em
alguns casos, poder trazer conseqncias inesperadas ou at desagradveis ao seu objeto.
Da, em casos deste tipo utiliza-se um construtor especfico sua classe, declarando-o portador de parmetros
que sejam fundamentais sua criao. Vejamos:
type
TCachorro = class(TAnimal)
Dono: string;
constructor Create(const Dono: string);
procedure Latir;
end;
implementation
constructor TCachorro.Create(const Dono: string);
begin
inherited Create;
Self.Dono := Dono;
end;
A partir de agora, nenhum cachorro no modelo poder ser instanciado sem que lhe haja o nome do dono. Nota-
se que o nosso construtor faz uma chamada ao construtor da ancestral, atravs do qualificador inherited (que
quer dizer herdado), que quem de fato ir criar a classe na memria. Veremos as chamadas inherited em
mais detalhes no prximo artigo. A varivel Self, vale informar, uma referncia para a instncia em questo,
fazendo diferenciar neste caso o que o atributo Dono do parmetro Dono.
Logo aproveitamos para falar que uma boa prtica de desenvolvimento de classes, sempre procurar obrigar a
informao dos dados importantes da criao no seu construtor. O uso de construtores especficos se faz
importante tambm quando se deseja executar alguma ao (cdigo) no momento da criao do objeto.
De igual maneira, podemos personalizar o destruidor da nossa classe, pela declarao abaixo:
type
TCachorro = class(TAnimal)
Dono: string;
constructor Create(const Dono: string);
destructor Destroy; override;
procedure Latir;
end;
implementation
constructor TCachorro.Create(const Dono: string);
begin
inherited Create;
Self.Dono := Dono;
end;
destructor TCachorro.Destroy;
begin
ShowMessage('Eu precisava muito exibir esta mensagem antes de er a destrudo!');
Inherited;
end;
Esta declarao faz a nossa classe sobrescrever o destruidor padro, chamando-o dentro do cdigo. Observe
que a chamada inherited, que quem de fato ir destruir o objeto, vem por ltimo. No prximo artigo, quando
estivermos falando de polimorfismo, explicaremos melhor estes detalhes. A assinatura do destruidor, vale
ressaltar, padro, no podendo ser acrescida de parmetros como fizemos com o Create.
Dica- Recomendamos aos desenvolvedores sempre evitarem o uso explcito do Destroy. ele no checa se a
referncia nula antes de destru-lo, o que pode ser desagradvel em caso de ser nula. Procure sempre usar o
mtodo Free derivado de TObject, que faz recorrncia ao Destroy, porm sem perder a segurana.
onsidera#es $inais
Novamente voltamos a dizer que no conclumos tudo o que temos a dizer sobre orientao a objetos com esse
artigo. Aqui, tratamos apenas um dos trs pilares da programao OO.
A herana um recurso extremamente poderoso, podendo ser em alguns momentos considerada por ns como
o mais importante dos conceitos relacionados orientao a objetos. A herana , tambm, uma parte crtica
da modelagem e do projeto de seu sistema. Um sistema bem modelado possui traos de herana bem
definidos, quanto ao propsito, classificao e s funcionalidades de cada classe. Um sistema mal modelado
pode acabar ficando comprometido.
Recomendo aos leitores interessados a trazer OO suas vidas de desenvolvedores, que pratiquem herana no
seu dia a dia. Comecem por classificar as coisas do mundo que existem ao seu redor, passando pelas classes de
negcio (isto , aquelas classes que s devero existir neste seu sistema, especificamente), at chegar em
classes consideradas utilitrias (ou seja, classes que fazem funes gerais, e podem ser usadas em vrios
sistemas diferentes). Uma boa prtica de herana leva excelncia de se desenvolver bons projetos, com boas
estruturas e pouco re-trabalho.
!ntroduo
Eis que aprendemos no primeiro dos artigos o que objeto. Aprendemos, completamente, no. Conseguimos
ter uma noo do assunto. Eis que no segundo, adentramos um pouco no universo da herana e os significados
dela para a analogia do mundo real. A herana, que estudamos na publicao anterior, o primeiro pilar dos
trs da OO. possvel que seja o mais importante, e por isso, fizemos questo de apresent-lo primeiro.
Mostrando um pouco do seu poder de classificao e dos recursos de reutilizao de cdigo que com ela vm
incorporados.
Nesta seo vamos abordar o polimorfismo, que mais um dos trs requisitos fundamentais a uma linguagem
ser considerada OO. Este recurso est diretamente ligado herana, e a incrementa de tal maneira que os
objetos que dele fazem uso adquirem um alto grau de flexibilidade e auto-suficincia. Nota-se que, pouco a
pouco, os programadores que fazem uso deste recurso acabam por ter cada vez menos preocupao e
responsabilidade sobre o comportamento de seus objetos.
O que polimorfismo, afinal?
Bom, paremos de ficar falando tanto em "polimorfismo para l e para c, sem dizer o que ele . Tentaremos
explic-lo primeiro em poucas linhas, embora tentar isto no seja nada fcil. O polimorfismo, ao grosso modo,
a capacidade de objetos pertencentes a uma mesma classe se comportarem diferentemente, a depender da
classe concreta a que eles pertencem. Fomos claros? Acho que ainda no...
Mas como temos certeza que nossos leitores so bastante espertos, sabemos que eles perceberam a palavra
"comportamento na explicao acima, embora no a tenham entendido direito. Comportamento, como se deve
ter imaginado, tem a ver com mtodos. E o polimorfismo se aplica exatamente aos mtodos. Vejamos um
exemplo de onde aplic-lo:
unit Unit1;
type
TVeiculo = class
Posicao: TPoint;
procedure MoverSe(const p: TPoint);
end;
TCarro = class(TVeiculo)
Pneus: Integer;
end;
TAviao = class(TVeiculo)
Asas: Integer;
end;
No nosso exemplo temos trs declaraes de classes, sendo uma ancestral, TVeiculo, e duas descendentes,
TCarro e TAviao. Nota-se que TVeiculo possui um mtodo MoverSe, que por deduo, ir deslocar o nosso
veculo em termos de posio. Nota-se ainda, que ambos os dois subtipos de veculos - carro e avio - se
movem.
Mas existe um problema no nosso modelo. Acontece que um avio se move de maneira diferente de um carro.
Se estivssemos falando, por exemplo, em termos de animao grfica, o nosso carro se moveria pela terra,
girando os pneus. O avio, por sua vez, se moveria pelo ar, girando as turbinas.
Em outras palavras, a modelagem est correta em termos das classes. O mtodo mover est relacionado com
sua classe mais ancestral, o TVeiculo, e ele descreve muito bem o que deve ser feito. Mas no descreve com
perfeio como isto deve ser feito. Alis, este um grande propsito do polimorfismo em relao s classes:
separar o que do como, ou os fins dos meios, como diria Maquiavel.
A proposta do polimorfismo aqui permitir que o carro e o avio possam se mover de forma diferente e
prpria, sem afetar a declarao e a abstrao da sua classe ancestral TVeiculo, mantendo ainda os dois tipos
de objeto fiis declarao desta classe.
Agora vamos corrigir nosso exemplo:
unit Unit1;
type
TVeiculo = class
Posicao: TPoint;
procedure MoverSe(const p: TPoint); virtual;
end;
TCarro = class(TVeiculo)
Pneus: Integer;
procedure MoverSe(const p: TPoint); override;
end;
TAviao = class(TVeiculo)
Asas: Integer;
procedure MoverSe(const p: TPoint); override;
end;
E vamos implement-lo:
implementation
procedure TVeiculo.MoverSe(const p: TPoint);
begin
//aqui nada interessa ser feito
end;
procedure TCarro.MoverSe(const p: TPoint);
begin
ShowMessage('Estou girando minhas rodas sobre o solo');
Posicao := p;
end;
procedure TAviao.MoverSe(const p: TPoint);
begin
ShowMessage('Estou girando minhas turbinas no ar');
Posicao := p;
end;
Agora vamos entender o que aconteceu. Primeiramente, declaramos o mtodo na classe TVeiculo com uma
diretiva virtual. Ainda no explicaremos o real significado disto neste pargrafo, mas por enquanto vamos
assumir que isto quer dizer que o mtodo polimrfico, ou seja, pode assumir outros comportamentos -
diferentemente dos mtodos estticos. Depois declaramos os mesmos mtodos nas classes descendentes com
uma diretiva override, que quem de fato ir implementar estes mtodos. E ento, implementamos os trs
mtodos em cdigo. O MoverSe de TVeiculo nada faz, e o MoverSe de cada tipo concreto de veculo o
implementa cada um sua maneira.
Pois eis que, caro quase-programador OO, ns demos implementaes diferentes de um mesmo mtodo para
diferentes subclasses desta mesma classe. Traduzindo esta frase, o que fizemos foi dizer a TVeiculo que ele se
move. Logo em seguida, demos a cada um dos subtipos de veculo o direito de se moverem cada um do seu
jeito, e ainda sob a mesma chamada de mtodo em TVeiculo.
Pois acontece que se referenciarmos uma instancia de TCarro por uma varivel do tipo TVeiculo, e mandarmos
que execute o mtodo MoverSe, o nosso veculo ir se mover como um carro. Eis que chegamos ao grande pulo
do gato da OO.
Vejamos outro exemplo:
unit Unit1;
const
PI = 3.141592654;
RAIZ_DE_DOIS = 1.4142135;
type
TFigura = class
Centro: TPoint;
constructor Create(const Pos: TPoint);
procedure Desenhar; virtual;
function Area: Real; virtual;
end;
TCirculo = class(TFigura)
Raio: Integer;
procedure Desenhar; override;
function Area: Real; override;
end;
TQuadrado = class(TFigura)
Lado: Integer;
procedure Desenhar; override;
function Area: Real; override;
end;
implementation
constructor TFigura.Create(const Pos: TPoint);
begin
inherited Create;
Centro := Pos;
end;
procedure TFigura.Desenhar;
begin
//nada aqui
end;
function TFigura.Area: Real;
begin
//nem aqui
end;
procedure TCirculo.Desenhar;
var Rect: TRect;
begin
Rect.Left := Centro.X - Round(Raio/RAIZ_DE_DOIS);
Rect.Top := Centro.Y - Round(Raio/RAIZ_DE_DOIS);
Rect.Right := Centro.X + Round(Raio/RAIZ_DE_DOIS);
Rect.Bottom := Centro.Y + Round(Raio/RAIZ_DE_DOIS);
Form1.Canvas.Ellipse(Rect);
end;
function TCirculo.Area: Real;
begin
Result := 2*PI*Raio;
end;
procedure TQuadrado.Desenhar;
var Rect: TRect;
begin
Rect.Left := Centro.X - Lado div 2;
Rect.Top := Centro.Y - Lado div 2;
Rect.Right := Centro.X + Lado div 2;
Rect.Bottom := Centro.Y + Lado div 2;
Form1.Canvas.Rectang(Rect);
end;
function TQuadrado.Area: Real;
begin
Result := Power(Lado, 2);
end;
Bom, este nosso ltimo exemplo talvez tenha trazido a coisa um pouco mais prtica, at porque imaginamos
que o leitor deve ter pensado por muitas vezes "mas para que eu vou querer animais, vegetais ou veculos
dentro do meu programa?. Este nosso exemplo traz tona o conceito de polimorfismo e tanto pode como deve
ser implementado para v-lo acontecer.
Como se pode notar, todas as chamadas execuo fazem referencia a um objeto do tipo Form1 que, no caso,
estamos nos referindo ao form principal do nosso exemplo. Entretanto isto no uma boa prtica de
programao, levando a uma situao que os analistas e engenheiros de software chamam de forte
acoplamento.
Forte acoplamento quer dizer que as suas classes so muito dependentes deste form, e uma mudana nesta
parte pode requerer uma mudana em todas as classes fortemente acopladas. Isto tambm compromete a
reutilizao de suas classes para outros projetos. Mas no vamos nos preocupar com isso aqui. Em prximas
publicaes iremos abordar o acoplamento e boas prticas de programao.
O cdigo abaixo uma sugesto de aplicao do cdigo acima, para que o leitor veja o polimorfismo em
funcionamento:
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
Figuras: array [1..10] of TFigura;
{ Public declarations }
end;
implementation
procedure TForm1.FormCreate(Sender: TObject);
var i: Integer; NovaPos: TPoint;
begin
Randomize;
for i := 1 to 10 do
begin
NovaPos.X := Random(Self.Width);
NovaPos.Y := Random(Self.Height); //sorteia a posio na janela
if Random(10) > 5 then //sorteia qual figura ir instanciar
Figuras[i] := TCirculo.Create(NovaPos)
else
Figuras[i] := TQuadrado.Create(NovaPos)
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var i: Integer;
begin
Self.Repaint;
for i := 1 to 10 do
Figuras[i].Desenhar;
end;
Note que, ao executar Button1Click(), todas as figuras sero desenhadas - cada uma a seu modo.
Mtodos Abstratos
No artigo anterior vimos que o que torna uma classe abstrata de fato a existncia de mtodos abstratos. Pois
bem que mtodos abstratos so aqueles que no possuem nenhuma implementao naquela classe, deixando
para serem implementados apenas pelas classes descendentes que o sobrescreverem.
Voltemos ao nosso ltimo exemplo, envolvendo crculos e quadrados. Note que o mtodo Area foi declarado
virtual na classe TFigura, e implementado nas classes TCirculo e TQuadrado. Entretanto, este mtodo ainda
implementado nesta classe, pois no foi declarado abstrato. Se o leitor notar, existe uma declarao vazia
deste mtodo em TFigura, por mais que nenhum cdigo tenha sido colocado ali dentro.
Acontece que se fosse instanciado, juntamente com os crculos e quadrados, um objeto concreto do tipo
TFigura, no momento em que o mtodo Area fosse invocado, ele seria executado de fato. Para ter certeza disto,
implemente-o da seguinte maneira:
procedure TFigura.Desenhar;
begin
ShowMessage('Erro: este mtodo no deveria ser chamado!!');
end;
E procure instanciar tambm objetos do tipo TFigura, usando o construtor TFigura.Create dentro do for-loop no
mtodo FormCreate. Voc perceber que este mtodo ser executado fiel como foi declarado na classe TFigura.
Porm, se quisermos declarar o mtodo Desenhar como abstrato, removeremos a sua implementao e
faremos a sua declarao da seguinte maneira:
type
TFigura = class
Centro: TPoint;
constructor Create(const Pos: TPoint);
procedure Desenhar; virtual; abstract;
function Area: Real; virtual;
end;
A razo da existncia de mtodos abstratos "obrigar que o desenvolvedor sempre implemente estes mtodos
nas classes inferiores, estabelecendo uma boa regra de consistncia no comportamento das classes.
Mas porque ento no declaramos logo todos os mtodos polimrficos como abstratos? Acontece que um
mtodo polimrfico no deve ser necessariamente abstrato. A classe pode ser abstrata, contendo mtodos
abstratos, e ainda assim conter um mtodo virtual no-abstrato entre eles. Dessa maneira, podemos
estabelecer mtodos polimrficos com um comportamento default para as outras classes, e a menos que a
classe descendente o sobrescreva, ela se comportar desta maneira. Deixaremos a cargo do leitor descobrir
situaes deste tipo. No se preocupe, no ser difcil encontr-las.
Em contrapartida, o uso de mtodos abstratos pode ser desagradvel caso o leitor realmente queira instanciar
aquela classe. A, novamente, cairemos na situao em que a classe no deveria ser definida abstrata, e a
chamada deste mtodo ir retornar um erro em tempo de compilao com a mensagem "abstract error. Como
j lamentamos no artigo anterior, a permissividade de se construir classes abstratas particular do Delphi.
Acessando os mtodos ori.inais
Suponhamos que voc est escrevendo uma classe descendente de outra, aplicando polimorfismo em alguns de
seus mtodos. Suponha ainda que seu mtodo no foi declarado abstrato, e ele possui uma implementao.
Vejamos o exemplo:
TCirculoPartido = class(TCirculo)
procedure Desenhar; override;
end;
Esta nova classe que inventamos precisa desenhar um crculo com duas linhas de dimetro, partindo-o em
forma de cruz. Sabe-se que, alm de ser considerada um crculo, ela tambm precisa de muitas das
implementaes j feitas em TCirculo, modificando apenas o mtodo Desenhar, e por isso fica bvia uma
situao de herana.
Ora, se vamos desenhar o crculo e seus dois dimetros, eis que faremos a mesma coisa que TCirculo.Desenhar
j fazia, com algo a mais. Para isso, existe um meio de evitar que tenhamos que reescrever todo este cdigo do
crculo dentro de TCirculoPartido novamente. Para isso chamamos a palavra reservada inherited com o nome do
mtodo. Vejamos como fica o nosso novo cdigo:
procedure TCirculoPartido.Desenhar;
var Origem, Destino: TPoint;
procedure DesenhaLinha;
begin
Form1.Canvas.MoveTo(Origem.X, Origem.Y);
Form1.Canvas.LineTo(Destino.X, Destino.Y);
end;
begin
inherited Desenhar; //que surte o mesmo efeito de chamar somente inherited;
Origem.Y := Centro.Y;
Origem.X := Centro.X - Raio;
Destino.Y := Centro.Y;
Destino.X := Centro.X + Raio;
DesenhaLinha;
Origem.X := Centro.X;
Origem.Y := Centro.Y - Raio;
Destino.X := Centro.X;
Destino.Y := Centro.Y + Raio;
DesenhaLinha;
end;
O objetivo do inherited informar ao compilador que o mtodo chamado deve ser o da classe imediatamente
superior (classe pai), ignorando um mesmo mtodo declarado na classe atual. Em Java equivale a chamar
super.
Mtodos virtuais versus Mtodos din"micos
Bom, fugindo um pouco da linha do assunto, h alguns pargrafos acima tivemos que usar uma palavra
reservada virtual como diretiva depois de um mtodo, para dizer ao compilador que ele era polimrfico. Eis que
agora vamos dizer o porqu.
Existem dois tipos de mtodos polimrficos, quanto implementao interna do compilador: mtodos virtuais
(virtual) e mtodos dinmicos (dynamic). viso do programador, eles so idnticos, e fazem exatamente a
mesma coisa. A diferena est em como o compilador recorre a estes mtodos.
Sabe-se que mtodos virtuais contra mtodos dinmicos so uma razo entre eficincia contra tamanho do
cdigo gerado. Muito embora voc perceba chamadas diretiva dynamic nos componentes da VCL, a prpria
Borland recomenda que se use o virtual na grande maioria dos casos. Para saber mais detalhes sobre estes dois
tipos de implementao, recomendamos que consulte a documentao da Borland, disponvel na ajuda do
Delphi, ou no site http://www.borland.com.
onsidera#es $inais
Demonstramos com este artigo a aplicao do polimorfismo na orientao a objetos e demos uma viso
superficial dos benefcios de se modelar um sistema OO, usando herana e polimorfismo. Como dissemos, o
polimorfismo capaz de fazer coisas fantsticas, retirando muitas das responsabilidades de implementao dos
programadores e trazendo-as para as classes. Se no existisse o polimorfismo, nossas classes ficariam, no
mnimo, extensas e cheias de testes condicionais, o que tornaria o cdigo, na melhor das hipteses, de difcil
compreenso.
Apenas com herana e polimorfismo j imaginamos que h todo um universo a ser aprendido e transformado
pela cabea ortodoxas dos programadores que no conheciam OO. Mas sem dvida, trata-se de uma excelente
maneira de programar, tanto a ttulo de facilidade e agilidade de codificao, quanto de manutenibilidade do
cdigo e eficincia. Enfim, no parece haver motivos conhecidos para no se aplicar OO, especialmente com os
benefcios trazidos pela herana e polimorfismo.
Na prxima publicao deveremos falar sobre encapsulamento, que o (nosso) terceiro pilar dos conceitos da
OO, abordando a visibilidade, e aplicando-os na prtica.
!ntroduo
Uma vez que lemos os trs primeiros artigos j publicados, ento j sabemos do que se tratam objetos,
instncias, classes concretas e abstratas, atributos, mtodos estticos e dinmicos, construtores, destruidores,
herana, polimorfismo, enfim, um monte de coisas. Mas ainda no sabemos o que encapsulamento - o
terceiro e ltimo dos pilares da OO. E dele que trataremos aqui.
Os objetos, nos sistemas de verdade - ao contrrio dos exemplos didticos que citamos at agora - costumam
ser numerosos, relativamente grandes, e repletos de atributos e mtodos. Isto pode torn-lo de difcil
compreenso caso no haja um bom critrio de privacidade para as partes do objeto consideradas internas. E
isto que prope o que estamos a tratar aqui sob o ttulo de encapsulamento.
O encapsulamento em resumo a maneira de fazer com que um objeto exponha apenas o que necessrio ser
exposto, mantendo como prprio e privado tudo aquilo que no seja de interesse de outros objetos que o
vejam por fora. Desta maneira poderemos separar "os dois mundos, a que nos referimos no ttulo - o mundo
exterior ao objeto e seu mundo privado.
Mantendo uma vida particular
Imagine um aparelho de TV. Ele normalmente constitudo de um painel, um visor, e alguns circuitos internos.
O painel o seu controle, acessvel ao seu usurio atravs de alguns botes. De igual maneira, o visor procura
exibir, diretamente para o telespectador, as imagens que lhe so requeridas. Estas duas partes so obviamente
necessrias ao acesso manual, satisfazendo muito bem o seu propsito.
Entretanto, determinados circuitos e controles no esto disponveis no painel ou na caixa deste equipamento.
Eles esto isolados dentro do aparelho, a fim de evitar o acesso manual, que poderia ser perigoso tanto para
quem tentasse acess-lo, quanto poderia comprometer o bom funcionamento do aparelho de TV.
Por isso importante que os objetos tenham alguns de seus elementos privados, dentre aqueles que so
declarados nos seus atributos e mtodos. Com esta privacidade ser possvel manter a compreenso, com um
cdigo mais limpo e mais legvel. Alm disso, o acesso a determinados atributos ou mtodos perigosos dos
objetos ser restrito.
O objetivo do encapsulamento tratar o objeto como uma caixa preta, que faz certas coisas, e disponibiliza
para que os seus programadores - que neste caso, devem ser tratados mais como "usurios - saibam o que
ele faz. Como o objeto faz, no seria de todo interessante saber. E isto um ponto fundamental para se reduzir
a complexidade do sistema viso do programador.
Pois eis que o exemplo do aparelho de TV uma boa analogia quanto ao encapsulamento dos objetos. Alm do
acesso total no ser muito conveniente, os usurios no costumam estar devidamente qualificados para acessar
as centenas de circuitos dentro do aparelho. Da mesma forma, os outros objetos de um programa certamente
no esto qualificados ao acesso total de todos os objetos.
lassificando os membros por visibilidade
Os membros de uma classe so classificados por trs escopos principais de visibilidade: pblicos (public),
privados (private) e protegidos (protected). No Delphi especificamente surge um tipo chamado published, que
uma variante do pblico, mas que no est relacionado especificamente com a OO, e sim com os componentes
da VCL. No trataremos de published neste artigo.
Os atributos e mtodos pblicos so aqueles que esto disponveis para tudo e todos acessarem, desde que
tenham visibilidade do objeto. Eles so visveis tanto externa quanto internamente ao objeto, e visam
disponibilizar a comunicao do objeto com os demais elementos do modelo. Membros so pblicos quando
declarados numa seo public da classe a que pertence.
Os membros privados por sua vez so aqueles que somente o objeto deve saber, no devendo estar disponveis
para os objetos externos. Eles devem ser declarados na seo private da classe. As sees podem ser
declaradas em qualquer ordem, desde que dispostas sempre antes dos membros relativos sua declarao.
Vejamos um exemplo:
type
TCarro = class
private
FMotor: TMotor;
procedure AlimentarBombaDeCombustivel;
procedure LiberarValvulaDeInjecao;
procedure InjetarCombustivel;
procedure AcionarPastilhas;
procedure DispararArranque;
public
Pneus: array [1..5] of TPneu;
procedure Ligar;
procedure Acelerar;
procedure Freiar;
end;
implementation
procedure TCarro.Ligar;
begin
DispararArranque;
InjetarCombustivel;
end;
procedure TCarro.Acelerar;
begin
InjetarCombustivel;
end;
procedure TCarro.Freiar;
begin
AcionarPastilhas;
end;
procedure TCarro.AlimentarBombaDeCombustivel;
begin
{aqui dever ser implementado o cdigo referente alimentao a bomba de
combustvel}
end;
procedure TCarro.InjetarCombustivel;
begin
AlimentarBombaDeCombustivel;
LiberarValvulaDeInjecao;
end;
procedure TCarro.AcionarPastilhas;
begin
{aqui dever ser implementado o cdigo referente ao acionamento sas pastilhas
de freio}
end;
procedure TCarro.DispararArranque;
begin
{aqui dever ser implementado o cdigo referente ao disparo do motor de
arranque}
end;
O que fizemos no exemplo? Bom, declaramos alguns mtodos e atributos privados e outros pblicos, de modo
que o que est privado - dentro da clusula private - no estar acessvel para uso por qualquer outro
elemento do sistema, seno dentro do prprio cdigo da classe - diferentemente do que est declarado no
public, que pode ser usado por qualquer um que consiga enxergar o objeto. Vale ressaltar que por conveno
declaramos os atributos privados comeando-os pela letra "F - do ingls Field (campo).
Note que existe uma razo para isso. Se o leitor perceber bem, todos os mtodos declarados pblicos esto
mais relacionados a funcionalidades externas do objeto, ou seja, algo que o usurio deve saber: "o que deve
pode feito. L esto os mtodos Ligar, Freiar e Acelerar do carro. Qual motorista no deveria fazer estas trs
coisas?
Em contrapartida, nada do que foi declarado em private deve ou precisa ser visto externamente ao carro.
Somente ele deve saber que precisa injetar combustvel ao acelerar, ou acionar as pastilhas de freio ao se
freiar. Isto "como deve ser feito, e no h por que isto interessar ao mundo de fora.
Um terceiro tipo de visibilidade dos membros de uma classe o protegido. Os membros protegidos, declarados
na seo protected, so privados ao objeto tanto quanto os declarados na seo private, exceto por um
detalhe. Eles so visveis a todas as classes descendentes, como se fossem membros privados delas.
Assim, seria interessante que instncias das classes TCarroPasseio e TCarroEsporte, descendentes de TCarro,
pudessem acessar alguns de seus elementos privados, uma vez que elas tambm pertencem a esta classe.
Agora vamos reformular o cabealho da nossa classe:
type
TCarro = class
private
FMotor: TMotor;
procedure AlimentarBombaDeCombustivel;
procedure LiberarValvulaDeInjecao;
procedure AcionarPastilhas;
protected
procedure InjetarCombustivel;
procedure DispararArranque;
public
Pneus: array [1..5] of TPneu;
procedure Ligar;
procedure Acelerar;
procedure Freiar;
end;
A razo desta mudana que o desenvolvedor desta classe imaginou o quanto seria til disponibilizar os
mtodos InjetarCombustivel e DispararArranque para as classes descendentes dela, e o fez ao declar-los como
protegidos. Note que os mtodos declarados em private realmente no precisariam serem disponibilizados, a
no ser que isto fosse julgado importante.
Propriedades- atributos a uma viso e/terna
A orientao a objetos diz, em seu conceito geral, que todo e qualquer atributo deve ser acessado apenas
atravs de mtodos pblicos. Da, dispor atributos publicamente no seria uma boa prtica de programao.
O objetivo desta restrio garantir a consistncia do estado do objeto. Convenhamos que qualquer objeto
com um bom encapsulamento saber, atravs destes mtodos, exatamente a melhor forma de manter a leitura
ou escrita de seus dados. Estes mtodos - popularmente conhecidos como gets e sets - pertencem a uma
filosofia bem respeitada por programadores Java em geral.
A Borland, por sua vez, adotou uma medida alternativa e interessante de promover a segurana de seus
atributos: o uso de propriedades. Esta medida se trata, na verdade, de encapsular os atributos sob mtodos
gets e sets. Isto dar ao desenvolvedor-usurio desta classe a "sensao de que ele est manipulando os
atributos internos do objeto diretamente, sem que de fato esteja. Vejamos:
type
TMinhaClasse = class
private
FAtributo: Integer;
FInicializado: Boolean;
procedure SetAtributo(const Value: Integer);
function GetAtributo: Integer;
public
property Atributo: Integer read GetAtributo write SetAtributo;
end;
var
MeuObjeto: TMinhaClasse;
implementation
procedure TMinhaClasse.SetAtributo(const Value: Integer);
begin
if (Value < 0) or (Value > 100) then
raise ELimiteException.Create('Este valor est fora dos limites' +
' estabelecidos para este objeto');
FAtributo := Value;
end;
function TMinhaClasse.GetAtributo: Integer;
begin
if not FInicializado then
raise EEstadoException.Create('Este objeto ainda no' +
' foi inicializado');
Result := FAtributo;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if MeuObjeto.Atributo <= 20 then
begin
ShowMessage('Este valor est muito baixo. Vamos aument-lo.');
MeuObjeto.Atributo := 35;
end;
end;
No cdigo acima, note que declaramos um atributo privado qualquer, FAtributo. Este atributo algo de ntimo
do objeto, e deve respeitar a algumas regras internas da classe, que nem todos os que acessam a classe
necessariamente devem saber. Mas querendo ou no, tero que respeitar. Propriedades so apenas uma forma
de abstrao do cdigo, e o compilador, na realidade, entende como se voc estivesse chamando os mtodos
GetAtributo e SetAtributo diretamente.
Nota-se que nossa classe garante a integridade de leitura e escrita do atributo FAtributo, atravs do uso de
excees. O acesso dele est sendo feito pela propriedade Atributo, que entendida pelo compilador como o
acesso aos mtodos GetAtributo e SetAtributo. No primeiro, garante-se que nenhuma instncia desta classe
ter FAtributo lido, sem que Finicializado esteja com o valor True. No segundo, garante-se que nunca lhe ser
atribudo um valor fora do limite de 0 a 100.
Dica: A IDE do Delphi possui um atalho para automaticamente criar os mtodos Gets e Sets, declarando-os na
propriedade, e criando o seu corpo automaticamente na seo implementation. Para isto, basta declarar a
propriedade com o tipo, e pressionar [control + shift + C].
de se observar ainda que as propriedades no necessariamente precisam representar um atributo-imagem
pelo lado de fora, uma vez que se tratam puramente de mtodos de entrada e sada. Elas podem ser apenas
uma abstrao de atributos, que podem ser fsicos ou no. O importante que o programador-usurio entenda
que est acessando uma propriedade do objeto. Assim criaremos propriedade virtual, e o programador usurio
da classe simplesmente acredita que est acionando um atributo. Exemplo:
type
TDatabase = class
private
procedure SetActive(const Value: Boolean);
function GetActive: Boolean;
protected
procedure Connect;
procedure Disconnect;
function IsConnected: Boolean;
public
property Active: Boolean read GetActive write SetActive;
end;
implementation
procedure TDatabase.SetActive(const Value: Boolean);
begin
if Value then
Connect
else
Disconnect;
end;
function TDatabase.GetActive: Boolean;
begin
Result := IsConnected;
end;
A sintaxe da declarao dos membros de leitura e escrita nas propriedades admite tanto mtodos quanto
atributos de mesmo tipo da propriedade. No sero estudados mais detalhes sobre propriedades aqui, porque
elas no pertencem filosofia do paradigma OO. Para ver este assunto mais detalhadamente, ns
recomendamos consultar a ajuda do Delphi.
0obrecar.a de Mtodos
Um outro conceito relevante quanto visibilidade de mtodos a sobrecarga. Sobrecarga - antes que o leitor
pergunte - a declarao de dois mtodos diferentes numa mesma classe, com o mesmo nome. O que deve
diferir os mtodos so os seus parmetros.
Se existe uma funcionalidade na sua classe que executa coisas diferentes em dois mtodos com parmetros
diferentes, mas que tenham um mesmo propsito, ento aparentemente no h impeclios para que o leitor d
o mesmo nome aos mtodos. Basta sobrecarreg-los. Para isso, usa-se a diretiva overload. A sobrecarga pode
inclusive facilitar a vida de quem ir usar a sua classe.
Vejamos um exemplo:
type
TColecao = class
public
procedure Adiciona(const Item: TItem); overload;
procedure Adiciona(const Colecao: TColecao); overload;
end;
A partir do cdigo de exemplo acima, podemos usar a chamada de mtodo Adiciona tanto para adicionar itens
quanto para adicionar Colees. Nota-se que o procedimento executado ser diferente em cada um dos
mtodos. A maneira com que se adiciona um TItem diferente de como se adicionar um TColecao. Mas, como
mais um caso de fins versus meios, o propsito o mesmo.
1isibilidade entre classes distintas
A rigor, nenhuma classe enxerga os atributos privados de outra. Assim diz a regra da boa vizinhana entre as
classes, na OO. Sabe-se que o ideal que cada classe conhea o menos possvel dos elementos internos da
outra na OO, mas existe um porm. Um no, dois, pois existem situaes em que pode ser necessrio se
extender a visibilidade entre as classes.
O primeiro caso refere-se aos membros protegidos. Ora convenhamos que se um mtodo declarado
protegido, isto significa que, muito embora no seja desejvel que ele seja visto por fora, interessante que as
subclasses faam uso dele. Portanto, o mtodo Tcontrol.Click, embora no seja pblico, necessrio que seja
acessvel tanto por um TEdit, quanto por um TButton ou por qualquer subclasse descendente de TControl.
O segundo porm tem a ver com classes amigas. A "amizade entre as classes algo conhecido no Ansi C++.
Ela se caracteriza por estabelecer, atravs da palavra reservada Friendly, uma espcie de relacionamento entre
duas ou mais classes, de modo que garanta a visibilidade de algumas de suas partes privadas entre elas.
No Delphi, esta cumplicidade entre as classes no declarada por meio de palavras reservadas, mas ela existe.
Duas classes passam a ter visibilidade mtua de seus atributos privados quando so declaradas na mesma unit.
Da, se for interessante compartilhar atributos privados entre duas ou mais classes, as declare sempre dentro
de um mesmo arquivo ".pas".
Entretanto, o acmulo de classes diversas numa mesma unidade de cdigo pode acabar comprometendo a
segurana de seus objetos. Da uma boa prtica de programao que prope dar nfase ao encapsulamento
procurar declarar as classes no mximo de arquivos fontes separados o possvel. Se no seu modelo no existe
um motivo bem forte para que uma classe enxergue os elementos privados de outra, ento as separe.
P+blico, privado ou prote.ido- quando devo declarar?
O discernimento do grau de visibilidade algo trivial para um programador OO experiente. Mas ainda no
para quem no est habituado com o encapsulamento. O critrio de quando declarar um atributo como pblico
ou como privado adquirido com a prtica. Mas sempre sugerimos tentar discernir, dentre as funcionalidades e
propriedades dos objetos, o que pode ser separado entre o que fazer dos detalhes de como se fazer. Os
primeiros so forte candidatos a serem privados ou protegidos.
Um critrio alternativo adotado por alguns desenvolvedores para definir o encapsulamento dos objetos, segue a
frase "tudo privado at que se prove o contrrio. Assim, declaram-se todos os mtodos como privados, at
que uma subclasse realmente precise acess-los, para que se tornem protegidos - ou at que realmente seja
preciso acess-los publicamente, e se tornarem pblicos. Esta filosofia, apesar de ser muito questionada,
garante um bom nvel de segurana do objeto.
Quanto aos atributos, recomendamos fortemente que nunca sejam declarados pblicos, sempre procurando
usar propriedades para a sua leitura e escrita externas. Esta uma boa prtica de OO.
onsidera#es $inais
Novamente volto a dizer que no pretendemos, com este artigo, ser citado na bibliografia da monografia de
ningum. Pretendemos somente clarear a idia sobre Orientao a Objetos - especialmente sobre o contexto
de encapsulamento e outros pontos relacionados com a visibilidade - aos iniciantes. Na medida do possvel,
tentamos fazer com que o mito de bicho de sete cabeas a que a OO tanto sofre preconceito seja quebrado.
O encapsulamento uma maneira bastante eficiente de diminuir a complexidade dos sistemas orientados a
objeto, e garantir a sua segurana e consistncia, principalmente quanto ao uso indevido de atributos e
mtodos dos objetos.
Outros tpicos relacionados Orientao a Objetos ainda esto por vir, dentro de uma mesma seqncia.
Pretendemos - em contradio com o que tnhamos planejado - publicar ainda mais trs artigos sobre o
assunto, abordando tpicos essenciais da OO, sempre aplicando-os em cdigo.

Você também pode gostar