Programação Orientada a Objeto
Conceito de POO
A programação tradicional (estruturada) leva o programador a pensar no fluxo do programa da primeira linha de código até a ultima, fixando o foco nos programas (procedimento e funções). Já os dados são colocados em segundo plano, sendo seu manuseio de forma passível e em alguns casos retirando sua importância do contexto.
Figura 1 – Arquitetura das linguagens tradicionais
O paradigma da programação orientada a objetos (POO) muda esse conceito, pois em vez do programador ficar pensando no fluxo do programa, ele deve analisar quais objetos estão relacionados a uma tarefa especifica e quais dados e métodos os torna único.
Figura 2 – Arquitetura da POO
Na prótica a POO proporciona inúmeros benefícios ao desenvolvimento de sistemas, tais como uma maneira eficiente de representar elementos do mundo real para a construção desses sistemas, usando-se para isso classes e objetos. Dessa maneira a reutilização de classes e objetos, alúm da sua manutenibilidade, diminuem os efeitos causados pelas manutenções dos sistemas.
Mas sé com o real conhecimento dos conceitos da orientação a objetos e sua utilização eficiente poderemos obter os benefícios propostos pela POO.
- Classe: É a representação de elementos do mundo real, sendo formado, basicamente, por atributos e métodos. Um atributo é o local onde de armazenamento dos dados, enquanto um método é responsável por realizar ações sobre um ou mais atributos, tais como obter ou modificar os seus valores.
- Objeto: É uma instância de uma classe. Para melhor entender tenha em mente uma analogia com uma variável e seu tipo, onde substituímos a variível pelo objeto e o tipo pela classe.
- Método: É uma sub-rotina interna de uma classe, ela é responsável por executar eventos na classe, estando, dessa maneira, ligadas a mesma.
- Evento: É uma ação, direta ou indireta, sofrida por uma classe. Um exemplo já bastante utilizado nesse curso é o evento OnClick, esse evento chama um método que tem sua funcionalidade implementada pelo programador.
- Abstração: É a capacidade de recriar os objetos do mundo real em um programa, mas levando em consideração somente o relevante ao mesmo. Um exemplo disso seria a utilização de um objeto cliente que é baseado na idéia de uma pessoa, que por sua vez é um ser humano. Não precisamos recriar todas as características de um ser humano, mas somente o relevante ao cliente e que é de interesse do programa.
- Encapsulamento: É a capacidade de tornar atributos e métodos de um objeto ocultos a outros objetos. Evidentemente que devem existir alguns métodos que permitam sua utilização, bastando somente saber quais são e como utilizá-los. Imagine que você está dirigindo um carro, para fazer isso você não precisa conhecer o funcionamento interno do motor, só precisa saber como e quando passa as marchas, entre outras funções.
- Herança: É a capacidade de uma classe definida como filha receber características já existentes de outra classe definida como pai ou mãe, em outras palavras, é a classificação hierárquica existente entre classes. Para entender melhor vamos analisar o exemplo da figura 3, nele temos a classe Mamíferos que dá origem as classes Cachorros e Humanos, essas duas novas classes herdam características da classe Mamíferos mas também têm características distintas entre si. Em seguida a classe Humanos dá origem a outras duas classes, Homens e Mulheres, que herdarão caracteríticas jí definidas na classe Humanas além de terem suas próprias características. Dessa maneira cada nova classe (subclasse) tem características mais especificas do que a classe de origem (superclasse).
- Polimorfismo: É a capacidade de classes diferentes responderem a mesma ordem, mas de maneira diferente. Ainda usando a figura 3 como exemplo, podemos ver que Homens e Cachorros são classes diferentes, mas ambos são capazes de correr, embora que o cachorro corra com as quatro patas, já o homem corre sobre os dois pés.
Figura 3 – Herança entre objetos
Exemplo de POO na Linguagem Delphi
Crie um novo projeto, renome o Form para FPrincipal, salve a Unit com o nome de UPrincipal e o projeto com o nome de AplicacaoPOO. Selecione o menu File > New > Unit – Delphi for Win32 para cria uma nova Unit sem um formulário anexo e salve essa com o nome de UClasses.
Na seção interface entre com o cédigo abaixo;
01 |
type |
02 |
TPessoa = class |
03 |
Nome: string; |
04 |
Fone: string; |
05 |
procedure Avaliar; |
06 |
constructor Create; |
07 |
destructor Destroy; |
08 |
end; |
Nesse código estamos usando o conceito de Abstração para criarmos uma nova classe. Como toda classe é um tipo comeéamos digitando a palavra reservada type.
Na linha 02 iniciamos a criação da nossa classe que é finalizado com a palavra reservada end; que se encontra na linha 08.
Nas linhas 03 e 04 declaramos dois campos (atributos) do tipo string.
Na linha 05 foi declarado o método Avaliação e nas linhas 06 e 07 são declarados dois outros métodos extremamente importantes. O mótodo constructor cria a instância do objeto, fazendo as alocações em memória e disponibilizando o objeto para uso, dessa maneira sempre que precisarmos instanciar um objeto devemos chamar esse método. Já o método destructor faz o inverso do constructor, ele destrói o objeto instanciado liberando a memória.
Observação |
Os métodos constructor e destructor são opcionais, eles foram colocados aqui por motivos didáticos, mas eles são implementados por default, uma vez que um objeto para ser instanciado e destruído necessita desses dois métodos. |
Com o prompot dentro da declaração da classe pressione Ctrl+Shift+C e entre com o seguinte código:
01 |
implementation |
02 |
|
03 |
uses Dialogs; |
04 |
|
05 |
{ TPessoa } |
06 |
|
07 |
procedure TPessoa.Avaliar; |
08 |
begin |
09 |
ShowMessage('Avaliação sendo executada'); |
10 |
end; |
11 |
|
12 |
constructor TPessoa.Create; |
13 |
begin |
14 |
Self.Nome := 'Novo Nome'; |
15 |
Self.Fone := 'Novo Fone'; |
16 |
end; |
17 |
|
18 |
destructor TPessoa.Destroy; |
19 |
begin |
20 |
Self.Nome := ''; |
21 |
Self.Fone := ''; |
22 |
end; |
23 |
|
24 |
end. |
Esse código é bem simples e praticamente dispensa explicações, o único detalhe novo que temos aqui é a palavra reservada Self, poderíamos ter atribuído valores aos campos Nome e Fone sem utilizá-la, mas para evitar ambigüidade utilizamos o Self para fazer uma referência implícita própria classe.
Volte para o FPrincipal, declare UClasses na cláusula uses da seção implementation, coloque um componente TButton e em seu evento OnClick entre com o código abaixo, compile e teste:
01 |
procedure TFPrincipal.Button1Click(Sender: TObject); |
02 |
var |
03 |
Aluno: TPessoa; |
04 |
begin |
05 |
Aluno := TPessoa.Create; |
06 |
ShowMessage( Aluno.Nome +#13+ Aluno.Fone ); |
07 |
Aluno.Nome := 'Tadeu'; |
08 |
Aluno.Fone := '1111-1111'; |
09 |
Aluno.Avaliar; |
10 |
ShowMessage( Aluno.Nome +#13+ Aluno.Fone ); |
11 |
Aluno.Destroy; |
12 |
end; |
Na linha 03 estamos declarando o objeto Aluno do tipo TPessoa. A linha 05 estamos instanciando o objeto Aluno. A linha 06 nos mostra o valor dos campos após o objeto ter sido instanciado. Nas linhas 07 e 08 estamos atribuindo novos valores nos campos do objeto. A linha 09 executa o método Avaliação, enquanto na linha 10 é mostrado os novos valores atribuídos aos campos.
Vó para a UClasses e abaixo da declaração da classe TPessoa crie duas classes descendentes da mesma como mostrado no código:
01 |
type |
02 |
TPessoa = class |
03 |
Nome: string; |
04 |
Fone: string; |
05 |
procedure Avaliar; |
06 |
constructor Create; |
07 |
destructor Destroy; |
08 |
end; |
09 |
|
10 |
TAluno = class(TPessoa) |
11 |
Turma: string; |
12 |
procedure Avaliar; |
13 |
constructor Create; |
14 |
destructor Destroy; |
15 |
end; |
16 |
|
17 |
TProf = class(TPessoa) |
18 |
Disciplina: string; |
19 |
procedure Avaliar; |
20 |
constructor Create; |
21 |
destructor Destroy; |
22 |
end; |
Nesse momento aplicamos o conceito de Herança, um vez que as classes TAluno e TProf são descendentes da classe TPessoa. Em seguida use o Ctrl+Shift+C nas classes e entre com o código em negrito:
01 |
implementation |
02 |
|
03 |
uses Dialogs; |
04 |
|
05 |
{ TPessoa } |
06 |
|
07 |
procedure TPessoa.Avaliar; |
08 |
begin |
09 |
ShowMessage('Avaliação sendo executada'); |
10 |
end; |
11 |
|
12 |
constructor TPessoa.Create; |
13 |
begin |
14 |
Self.Nome := 'Novo Nome'; |
15 |
Self.Fone := 'Novo Fone'; |
16 |
end; |
17 |
|
18 |
destructor TPessoa.Destroy; |
19 |
begin |
20 |
Self.Nome := ''; |
21 |
Self.Fone := ''; |
22 |
end; |
23 |
|
24 |
{ TAluno } |
25 |
|
26 |
procedure TAluno.Avaliar; |
27 |
begin |
28 |
ShowMessage('Respondendo a prova'); |
29 |
end; |
30 |
|
31 |
constructor TAluno.Create; |
32 |
begin |
33 |
Self.Nome := 'Novo Aluno'; |
34 |
Self.Turma := 'Nova Turma'; |
35 |
end; |
36 |
|
37 |
destructor TAluno.Destroy; |
38 |
begin |
39 |
Self.Turma := ''; |
40 |
end; |
41 |
|
42 |
{ TProf } |
43 |
|
44 |
procedure TProf.Avaliar; |
45 |
begin |
46 |
ShowMessage('Aplicando a prova'); |
47 |
end; |
48 |
|
49 |
constructor TProf.Create; |
50 |
begin |
51 |
Self.Disciplina := 'Nova Disciplina'; |
52 |
end; |
53 |
|
54 |
destructor TProf.Destroy; |
55 |
begin |
56 |
Self.Disciplina := ''; |
57 |
end; |
58 |
|
59 |
end. |
Novamente volte para o FPrincipal, mude o evento OnClick do TButton, compile e teste:
01 |
procedure TFPrincipal.Button1Click(Sender: TObject); |
02 |
var |
03 |
Pessoa: TPessoa; |
04 |
Aluno: TAluno; |
05 |
Prof: TProf; |
06 |
begin |
07 |
// Trabalhando com o objeto Pessoa |
08 |
Pessoa := TPessoa.Create; |
09 |
ShowMessage( 'Objeto Pessoa' +#13+ |
10 |
Pessoa.Nome +#13+ Pessoa.Fone ); |
11 |
Pessoa.Nome := 'Tadeu'; |
12 |
Pessoa.Fone := '1111-1111'; |
13 |
Pessoa.Avaliar; |
14 |
ShowMessage( 'Objeto Pessoa' +#13+ |
15 |
Pessoa.Nome +#13+ Pessoa.Fone ); |
16 |
Pessoa.Destroy; |
17 |
|
18 |
// Trabalhando com o objeto Aluno |
19 |
Aluno := TAluno.Create; |
20 |
ShowMessage( 'Objeto Aluno' +#13+ |
21 |
Aluno.Nome +#13+ Aluno.Fone +#13+ Aluno.Turma ); |
22 |
Aluno.Nome := 'José'; |
23 |
Aluno.Fone := '2222-2222'; |
24 |
Aluno.Turma := 'Comp02'; |
25 |
Aluno.Avaliar; |
26 |
ShowMessage( 'Objeto Aluno' +#13+ |
27 |
Aluno.Nome +#13+ Aluno.Fone +#13+ Aluno.Turma ); |
28 |
Aluno.Destroy; |
29 |
|
30 |
// Trabalhando com o objeto Prof |
31 |
Prof := TProf.Create; |
32 |
ShowMessage( 'Objeto Prof' +#13+ |
33 |
Prof.Nome +#13+ Prof.Fone +#13+ Prof.Disciplina ); |
34 |
Prof.Nome := 'Maria'; |
35 |
Prof.Fone := '3333-3333'; |
36 |
Prof.Disciplina := 'Linguagem II'; |
37 |
Prof.Avaliar; |
38 |
ShowMessage( 'Objeto Prof' +#13+ |
39 |
Prof.Nome +#13+ Prof.Fone +#13+ Prof.Disciplina ); |
40 |
Prof.Destroy; |
41 |
end; |
Note que mesmo sem termos declarado os campos Nome e Fone nas subclasses, elas herdaram esses campos da superclasse, dessa maneira a cada novo nível criada mais específico vai ficando a subclasse. O mesmo acontece com métodos que são declarados na superclasse e não o são na subclasse, mas no nosso exemplo redefinimos os métodos da superclasse, aplicando assim o conceito de Polimorfismo. Linguagem Delphi garante o funcionamento correto do método desejado através do uso das palavras reservadas mostrada a tabela.
Palavra reservada |
Uso |
static |
Os métodos estáticos usam a implementação feita na subclasse que instância o objeto. Por default todo método é estático. |
virtual |
Embora os métodos virtuais usem a implementação feita na subclasse que instância o objeto, também podem ativar a implementação da superclasse. |
dynamic |
Semelhante ao anterior, o que os diferencia é que no caso anterior a velocidade de acesso é otimizada, enquanto no dynamic a otimização é feita em cima do código. Vale ressaltar que a diretiva virtual é a forma mais comum e eficiente de implementar o polimorfismo. |
override |
Essa diretiva garante que apenas uma implementação exista na classe descendente, ocultando as implementações das classes ancestrais. A assinatura do método deve ser igual em todas as classes descendentes e ancestrais, isso quer dizer que os métodos devem ter o mesmo nome e os seus parâmetros devem ter o mesmo número, tipo e ordem. Essa diretiva só pode ser usada com os métodos virtuais e dinâmicos. |
overload |
Essa diretiva permite que os métodos tenham assinaturas diferentes e não oculta as implementações das classes ancestrais, podendo ser usada com qualquer método – estético, virtual ou dinâmico. |
reintroduce |
Assim como a anterior permite que os métodos tenham assinaturas diferentes, mas nesse caso os métodos ancestrais sáo ocultados. Essa diretiva só pode ser usada com os métodos virtuais. |
abstract |
Essa diretiva é usada para determinar que o método não será implementado na classe onde foi declarada. Sua implementação deverá ser feita nas classes descendentes. Quando definimos um método como abstrato devemos ter em mente que a classe passa também a ser abstrata, não pode ser instanciada. Essa diretiva só pode ser usada em métodos virtuais e dinâmicos. |
final |
O uso dessa diretiva impede que classes descendentes redefinam métodos ancestrais. |
inherited |
Essa diretiva é usada para fazer uma chamada ao método ancestral e reaproveitar sua funcionalidade. |
Vamos tornar os métodos da nossa superclasse em métodos virtuais:
01 |
unit UClasses; |
02 |
|
03 |
interface |
04 |
|
05 |
type |
06 |
TPessoa = class |
07 |
Nome: string; |
08 |
Fone: string; |
09 |
procedure Avaliar; virtual; |
10 |
constructor Create; virtual; |
11 |
destructor Destroy; virtual; |
12 |
end; |
13 |
|
14 |
TAluno = class(TPessoa) |
15 |
Turma: string; |
16 |
procedure Avaliar; override; |
17 |
constructor Create; override; |
18 |
destructor Destroy; override; |
19 |
end; |
20 |
|
21 |
TProf = class(TPessoa) |
22 |
Disciplina: string; |
23 |
procedure Avaliar; override; |
24 |
constructor Create; override; |
25 |
destructor Destroy; override; |
26 |
end; |
27 |
|
28 |
implementation |
29 |
|
30 |
uses Dialogs; |
31 |
|
32 |
{ TPessoa } |
33 |
|
34 |
procedure TPessoa.Avaliar; |
35 |
begin |
36 |
ShowMessage('Avaliação sendo executada'); |
37 |
end; |
38 |
|
39 |
constructor TPessoa.Create; |
40 |
begin |
41 |
Self.Nome := 'Novo Nome'; |
42 |
Self.Fone := 'Novo Fone'; |
43 |
end; |
44 |
|
45 |
destructor TPessoa.Destroy; |
46 |
begin |
47 |
Self.Nome := ''; |
48 |
Self.Fone := ''; |
49 |
end; |
50 |
|
51 |
{ TAluno } |
52 |
|
53 |
procedure TAluno.Avaliar; |
54 |
begin |
55 |
inherited; |
56 |
ShowMessage('Respondendo a prova'); |
57 |
end; |
58 |
|
59 |
constructor TAluno.Create; |
60 |
begin |
61 |
inherited; |
62 |
Self.Turma := 'Nova Turma'; |
63 |
end; |
64 |
|
65 |
destructor TAluno.Destroy; |
66 |
begin |
67 |
Self.Turma := ''; |
68 |
inherited; |
69 |
end; |
70 |
|
71 |
{ TProf } |
72 |
|
73 |
procedure TProf.Avaliar; |
74 |
begin |
75 |
inherited; |
76 |
ShowMessage('Aplicando a prova'); |
77 |
end; |
78 |
|
79 |
constructor TProf.Create; |
80 |
begin |
81 |
inherited; |
82 |
Self.Disciplina := 'Nova Disciplina'; |
83 |
end; |
84 |
|
85 |
destructor TProf.Destroy; |
86 |
begin |
87 |
Self.Disciplina := ''; |
88 |
inherited; |
89 |
end; |
90 |
|
91 |
end. |
Vemos uma das vantagens da POO, mudamos as classes mas não precisamos mudar nada no FPrincipal, para as alterações entrarem em vigor apenas compile e teste.
O código a seguir transforma a superclasse TPessoa em uma classe abstrata, obrigando as subclasses TAluno e TProf a implementar o método abstrato:
01 |
type |
02 |
TPessoa = class |
03 |
Nome: string; |
04 |
Fone: string; |
05 |
procedure Avaliar; virtual; |
06 |
procedure Lancar_Nota; virtual; abstract; |
07 |
constructor Create; virtual; |
08 |
destructor Destroy; virtual; |
09 |
end; |
10 |
|
11 |
TAluno = class(TPessoa) |
12 |
Turma: string; |
13 |
procedure Avaliar; override; |
14 |
procedure Lancar_Nota; override; |
15 |
constructor Create; override; |
16 |
destructor Destroy; override; |
17 |
end; |
18 |
|
19 |
TProf = class(TPessoa) |
20 |
Disciplina: string; |
21 |
procedure Avaliar; override; |
22 |
procedure Lancar_Nota; override; |
23 |
constructor Create; override; |
24 |
destructor Destroy; override; |
25 |
end; |
Pressione Crtl+Shift+C dentro das classes TAluno e TProf, em seguida entre com código mostrado:
01 |
procedure TAluno.Lancar_Nota; |
02 |
var |
03 |
Nota: string; |
04 |
begin |
05 |
InputQuery('Nota', 'Qual foi a nota?', Nota); |
06 |
end; |
07 |
|
08 |
procedure TProf.Lancar_Nota; |
09 |
var |
10 |
Aluno, Nota: string; |
11 |
begin |
12 |
InputQuery('Aluno', 'Nome do aluno?', Aluno); |
13 |
InputQuery('Nota', 'Qual foi a nota do aluno ' + |
14 |
Aluno + '?', Nota); |
15 |
end; |
Mude o evento OnClick do TButton que está FPrincipal, compile, teste e verifique o erro que dá:
01 |
procedure TFPrincipal.Button1Click(Sender: TObject); |
02 |
var |
03 |
Pessoa: TPessoa; |
04 |
Aluno: TAluno; |
05 |
Prof: TProf; |
06 |
begin |
07 |
// Trabalhando com o objeto Pessoa |
08 |
Pessoa := TPessoa.Create; |
09 |
ShowMessage( 'Objeto Pessoa' +#13+ |
10 |
Pessoa.Nome +#13+ Pessoa.Fone ); |
11 |
Pessoa.Nome := 'Tadeu'; |
12 |
Pessoa.Fone := '1111-1111'; |
13 |
Pessoa.Avaliar; |
14 |
Pessoa.Lancar_Nota; |
15 |
ShowMessage( 'Objeto Pessoa' +#13+ |
16 |
Pessoa.Nome +#13+ Pessoa.Fone ); |
17 |
Pessoa.Destroy; |
18 |
|
19 |
// Trabalhando com o objeto Aluno |
20 |
Aluno := TAluno.Create; |
21 |
ShowMessage( 'Objeto Aluno' +#13+ |
22 |
Aluno.Nome +#13+ Aluno.Fone +#13+ Aluno.Turma ); |
23 |
Aluno.Nome := 'José'; |
24 |
Aluno.Fone := '2222-2222'; |
25 |
Aluno.Turma := 'Comp02'; |
26 |
Aluno.Avaliar; |
27 |
Aluno.Lancar_Nota; |
28 |
ShowMessage( 'Objeto Aluno' +#13+ |
29 |
Aluno.Nome +#13+ Aluno.Fone +#13+ Aluno.Turma ); |
30 |
Aluno.Destroy; |
31 |
|
32 |
// Trabalhando com o objeto Prof |
33 |
Prof := TProf.Create; |
34 |
ShowMessage( 'Objeto Prof' +#13+ |
35 |
Prof.Nome +#13+ Prof.Fone +#13+ Prof.Disciplina ); |
36 |
Prof.Nome := 'Maria'; |
37 |
Prof.Fone := '3333-3333'; |
38 |
Prof.Disciplina := 'Linguagem II'; |
39 |
Prof.Avaliar; |
40 |
Prof.Lancar_Nota; |
41 |
ShowMessage( 'Objeto Prof' +#13+ |
42 |
Prof.Nome +#13+ Prof.Fone +#13+ Prof.Disciplina ); |
43 |
Prof.Destroy; |
44 |
end; |
A classe TPessoa não poderia ter sido instanciado pois ela é uma classe abstrata, mas caso se deseje utilizá-la e desprezar a regra de náo poder instanciar uma classe abstrata, basta comentar a linha 14 com a barra dupla.
Iremos agora implementar o conceito de Encapsulamento nas nossas classes, em outras palavras, vamos deixar as nossas classes com o mínimo de funcionalidade visível, mas elas devem ter fácil acoplamento e uma interface acessível. Para os puristas de POO, todos os campos e alguns métodos não podem ser acessados diretamente do meio da classe. Classes e objetos distintos só terão acesso a alguns métodos que permitam a interação com os mesmos. Para isso a Linguagem Delphi implementa níveis de visibilidade dentro da classe.
Palavra reservada |
Visibilidade |
private |
Os campos e métodos declarados nesse escopo só são acessÃveis pela classe a qual pertencem e pelas classes "amigas". Classes "amigas" são as classes definidas na mesma Unit. |
strict private |
Semelhante ao anterior, só que nesse caso é vetado o acesso das classes "amigas" |
protected |
Esse escopo define que os campos e métodos nele declarados são acessíveis pela própria classe e por seus descendentes, além das classes "amigas". |
strict protected |
Semelhante ao anterior, só que nesse caso é vetado o acesso das classes "amigas". |
puclic |
Define que os campos e métodos sejam acessíveis por qualquer classe. |
published |
A visibilidade dos campos e métodos desse escopo são semelhantes ao anterior, a diferença é que os mesmos são publicados no Object Inspector. |
automated |
Também semelhante ao public, mas nesse caso são geradas informações de tipo automático (automation type information) normalmente usados em classes Windows. Os Automation Objects que permitem trabalhar com objetos de aplicações como Word e Excel são exemplos de automated. |
Modifique as classes para podemos incorporar os níveis de visibilidade recomendada pela Encapsulamento.
01 |
type |
02 |
TPessoa = class |
03 |
private |
04 |
FNome: string; |
05 |
FFone: string; |
06 |
public |
07 |
procedure Avaliar; virtual; |
08 |
procedure Lancar_Nota; virtual; abstract; |
09 |
procedure SetFone(pNome: string); |
10 |
function GetFone: string; |
11 |
constructor Create; virtual; |
12 |
destructor Destroy; virtual; |
13 |
published |
14 |
property Nome: string |
15 |
read FNome write FNome; |
16 |
end; |
17 |
|
18 |
 TAluno = class(TPessoa) |
19 |
private |
20 |
FTurma: string; |
21 |
public |
22 |
procedure Avaliar; override; |
23 |
procedure Lancar_Nota; override; |
24 |
procedure SetTurma(pTurma: string); |
25 |
function GetTurma: string; |
26 |
constructor Create; override; |
27 |
destructor Destroy; override; |
28 |
published |
29 |
property Turma: string |
30 |
read GetTurma write SetTurma; |
31 |
end; |
32 |
|
33 |
TProf = class(TPessoa) |
34 |
private |
35 |
FDisciplina: string; |
36 |
FCurso: string; |
37 |
public |
38 |
procedure Avaliar; override; |
39 |
procedure Lancar_Nota; override; |
40 |
procedure SetDisciplina(pDisciplina: string); |
41 |
function GetCurso: string; |
42 |
constructor Create; override; |
43 |
destructor Destroy; override; |
44 |
published |
45 |
property Disciplina: string |
46 |
read FDisciplina write SetDisciplina; |
47 |
property Curso: string |
48 |
read GetCurso write FCurso; |
49 |
end; |
Implementamos os níveis de acesso private, public e published nas três classes, note que os campos mudaram de nome (foi incluída letra F no seu inicio), além da inclusão de um novo campo na classe TProf. Isso obriga a alteração dos nomes dos campos em todas as partes das classes, mas essas alteraçães só devem ser feitas dentro da UClasses, no momento não mude nada na UPrincipal.
Todos os campos foram implementados com visibilidade private, dessa maneira foi atendido uma exigência do encapsulamento que diz "nenhum campo pode ser acessado diretamente".
Os métodos foram colocados com visibilidade public, pois todos os métodos apresentados são usados como ponto de acoplamento entre a classe e outras classes e objetos. Foram criados novos métodos do tipo Get e Set, esses métodos servem para ler e escrever, respectivamente, dados de um campo dentro da classe.
Na visibilidade published temos outra forma de manipulação de campo que pode ser usada na Linguagem Delphi, as propriedades. Uma propriedade pode realizar leitura e escrita num campo de forma "indireta". Declaramos nas linhas 14 e 15 a propriedade Nome que ler(write) e escreve(get) dados no campo FNome da classes TPessoa. Foram declaradas propriedades mesclando o uso dos Gets e Sets.
Observação |
Caso se deseje cria uma propriedade de somente leitura (read-only) basta omitir a diretiva write, se for o caso de se ter uma propriedade de somente gravação (write-only) omita a diretiva read. |
Segue as mudanças acontecidas na seção implementation da UClasses:
001 |
{ TPessoa } |
002 |
|
003 |
procedure TPessoa.Avaliar; |
004 |
begin |
005 |
ShowMessage('Avaliação sendo executada'); |
006 |
end; |
007 |
|
008 |
constructor TPessoa.Create; |
009 |
begin |
010 |
Self.FNome := 'Novo Nome'; |
011 |
Self.FFone := 'Novo Fone'; |
012 |
end; |
013 |
|
014 |
destructor TPessoa.Destroy; |
015 |
begin |
016 |
Self.FNome := ''; |
017 |
Self.FFone := ''; |
018 |
end; |
019 |
|
020 |
procedure TPessoa.SetFone(pNome: string); |
021 |
begin |
022 |
FFone := pNome; |
023 |
end; |
024 |
|
025 |
function TPessoa.GetFone: string; |
026 |
begin |
027 |
Result := FFone; |
028 |
end; |
029 |
|
030 |
{ TAluno } |
031 |
|
032 |
procedure TAluno.Avaliar; |
033 |
begin |
034 |
inherited; |
035 |
ShowMessage('Respondendo a prova'); |
036 |
end; |
037 |
|
038 |
constructor TAluno.Create; |
039 |
begin |
040 |
inherited; |
041 |
Self.FTurma := 'Nova Turma'; |
042 |
end; |
043 |
|
044 |
destructor TAluno.Destroy; |
045 |
begin |
046 |
Self.FTurma := ''; |
047 |
inherited; |
048 |
end; |
049 |
|
050 |
procedure TAluno.Lancar_Nota; |
051 |
var |
052 |
Nota: string; |
053 |
begin |
054 |
InputQuery('Nota', 'Qual foi a nota?', Nota); |
055 |
end; |
056 |
|
057 |
procedure TAluno.SetTurma(pTurma: string); |
058 |
begin |
059 |
FTurma := pTurma; |
060 |
end; |
061 |
|
062 |
function TAluno.GetTurma: string; |
063 |
begin |
064 |
Result := FTurma; |
065 |
end; |
066 |
|
067 |
{ TProf } |
068 |
|
069 |
procedure TProf.Avaliar; |
070 |
begin |
071 |
inherited; |
072 |
ShowMessage('Aplicando a prova'); |
073 |
end; |
074 |
|
075 |
constructor TProf.Create; |
076 |
begin |
077 |
inherited; |
078 |
Self.FDisciplina := 'Nova Disciplina'; |
079 |
Self.FCurso := 'Novo Curso'; |
080 |
end; |
081 |
|
082 |
destructor TProf.Destroy; |
083 |
begin |
084 |
Self.FDisciplina := ''; |
085 |
Self.FCurso := ''; |
086 |
inherited; |
087 |
end; |
088 |
|
089 |
procedure TProf.Lancar_Nota; |
090 |
var |
091 |
Aluno, Nota: string; |
092 |
begin |
093 |
InputQuery('Aluno', 'Nome do aluno?', Aluno); |
094 |
InputQuery('Nota', 'Qual foi a nota do aluno ' + |
095 |
Aluno + '?', Nota); |
096 |
end; |
097 |
|
098 |
procedure TProf.SetDisciplina(pDisciplina: string); |
099 |
begin |
100 |
FDisciplina := pDisciplina; |
101 |
end; |
102 |
|
103 |
function TProf.GetCurso: string; |
104 |
begin |
105 |
Result := FCurso; |
106 |
end; |
Para finalizar vamos muda o código do evento OnClick do TButton que está no FPrincipal, em seguida compile e teste:
01 |
procedure TFPrincipal.Button1Click(Sender: TObject); |
02 |
var |
03 |
Aluno: TAluno; |
04 |
Prof: TProf; |
05 |
begin |
06 |
// Trabalhando com o objeto Aluno |
07 |
Aluno := TAluno.Create; |
08 |
ShowMessage( 'Objeto Aluno' +#13+ |
09 |
Aluno.Nome +#13+ Aluno.GetFone +#13+ Aluno.Turma ); |
10 |
Aluno.Nome := 'José'; |
11 |
Aluno.SetFone('2222-2222'); |
12 |
Aluno.Turma := 'Comp02'; |
13 |
Aluno.Avaliar; |
14 |
Aluno.Lancar_Nota; |
15 |
ShowMessage( 'Objeto Aluno' +#13+ |
16 |
Aluno.Nome +#13+ Aluno.GetFone +#13+ Aluno.Turma ); |
17 |
Aluno.Destroy; |
18 |
|
19 |
// Trabalhando com o objeto Prof |
20 |
Prof := TProf.Create; |
21 |
ShowMessage( 'Objeto Prof' +#13+ |
22 |
Prof.Nome +#13+ Prof.GetFone +#13+ Prof.Disciplina +#13+ |
23 |
Prof.Curso ); |
24 |
Prof.Nome := 'Maria'; |
25 |
Prof.SetFone('3333-3333'); |
26 |
Prof.Disciplina := 'Linguagem II'; |
27 |
Prof.Curso := 'Análise'; |
28 |
Prof.Avaliar; |
29 |
Prof.Lancar_Nota; |
30 |
ShowMessage( 'Objeto Prof' +#13+ |
31 |
Prof.Nome +#13+ Prof.GetFone +#13+ Prof.Disciplina +#13+ |
32 |
Prof.Curso ); |
33 |
Prof.Destroy; |
34 |
end; |