Classes em Delphi
Bom dia! Estou aprendendo um pouco de OO com delphi e criei uma classe simples para validar os campos de um form. Como não conheço muito de OO gostaria de saber se estou no caminho certo e se tem alguma coisa que eu esqueci ou que possa ser melhorada. Segue abaixo a classe e sua utilização:
------------------------------------------------------------------------------------------------------------------------------
Abaixo a utilização:
Desde já, muito Obrigado!
unit uValidar;
interface
uses
Windows, SysUtils, Forms, Classes, Controls;
type
TValidar = class
private
FGravar: Boolean;
function getGravar:Boolean;
public
function Data(Data: String; ShowMsg: Boolean; Menssagem: String; Componente: TObject = nil): Boolean;
function CampoObrigatorio(Campo: String; ShowMsg: Boolean; Menssagem: String; Componente: TObject = nil): Boolean;
property Gravar: Boolean read getGravar;
constructor Create;
end;
implementation
{ TValidar }
// *****************************************************************************
// Função para validaçáo de campo obrigatório
// *****************************************************************************
function TValidar.CampoObrigatorio(Campo: String; ShowMsg: Boolean;
Menssagem: String; Componente: TObject): Boolean;
begin
if Campo = '' then
begin
FGravar:= false;
Result := false;
if (Componente is TWinControl) then
TWinControl(Componente).SetFocus;
if ShowMsg then
Application.MessageBox(Pchar(Menssagem), 'Atenção',MB_ICONINFORMATION + MB_OK);
end
else
Result:=True;
end;
// *****************************************************************************
// Constructor para inicialização da variável FGravar
// *****************************************************************************
constructor TValidar.Create;
begin
FGravar := True;
end;
// *****************************************************************************
// Função para validaçáo de datas
// *****************************************************************************
function TValidar.Data(Data: String; ShowMsg: Boolean; Menssagem: String; Componente: TObject = nil): Boolean;
var
Aux: TDateTime;
begin
if (TryStrToDate(Data,Aux))then
begin
Result := True
end
else
begin
Result := False;
FGravar := False;
if (Componente is TWinControl) then
TWinControl(Componente).SetFocus;
if ShowMsg = True then
Application.MessageBox(Pchar(Menssagem), 'Atenção',MB_ICONINFORMATION + MB_OK);
end;
end;
// *****************************************************************************
// Função para ler a variável FGravar
// *****************************************************************************
function TValidar.getGravar: Boolean;
begin
Result := FGravar;
end;
end.
------------------------------------------------------------------------------------------------------------------------------
Abaixo a utilização:
procedure TForm1.Button1Click(Sender: TObject);
var
Validar : TValidar;
begin
Validar := TValidar.Create();
Validar.Data(Edit1.Text,true,'Data Inválida',Form1.Edit1);
if Validar.Gravar then
ShowMessage('Gravar')
else
ShowMessage('Não Gravar');
FreeAndNil(Validar);
end;
Desde já, muito Obrigado!
Walter Desidera
Curtidas 0
Melhor post
Raimundo Melo
12/05/2010
Olá, boa tarde, fico feliz em saber que tem alguém realmente querendo aprender....
Eu fiz algumas melhorias que podem ser válidas, vc disse que ainda está começando...darei algumas dicas de melhorias..
Por exemplo....Eu percebi q essa classe TValidar, poder ter métodos estáticos...ou seja...vc não precisa instanciar a classe para ter acesso aos métodos....
Eu fiz algumas melhorias....
A classe ficaria assim...
a implementação da classe ficaria assim..
E um exemplo de uso...seria assim..
Mts vezes usar métodos estáticos tbm resolvem nossos problemas....
Espero ter ajudado....flw
Eu fiz algumas melhorias que podem ser válidas, vc disse que ainda está começando...darei algumas dicas de melhorias..
Por exemplo....Eu percebi q essa classe TValidar, poder ter métodos estáticos...ou seja...vc não precisa instanciar a classe para ter acesso aos métodos....
Eu fiz algumas melhorias....
A classe ficaria assim...
Type TValidar = classpublic Class function Data(Data: String; ShowMsg: Boolean; Menssagem: String; Componente: TObject = nil): Boolean;//Método estático. Class function CampoObrigatorio(Campo: String; ShowMsg: Boolean; Menssagem: String; Componente: TObject = nil): Boolean;//Método estático. constructor Create; end;
a implementação da classe ficaria assim..
{ TValidar }
// *****************************************************************************// Função para validaçáo de campo obrigatório// *****************************************************************************
Class function TValidar.CampoObrigatorio(Campo: String; ShowMsg: Boolean; Menssagem: String; Componente: TObject): Boolean;
begin
if Campo = '' then
begin
Result := false;
if (Componente is TWinControl) then
TWinControl(Componente).SetFocus;
if ShowMsg then
Application.MessageBox(Pchar(Menssagem), 'Atenção',MB_ICONINFORMATION + MB_OK);
end
else
Result:=True;
end;
// *****************************************************************************// Constructor para inicialização da variável FGravar// *****************************************************************************
constructor TValidar.Create;
begin
Inherited Create(); //Chama o método Create da super Classe, no caso, TObject.//FGravar := True;
end;
// *****************************************************************************// Função para validaçáo de datas// *****************************************************************************
Class function TValidar.Data(Data: String; ShowMsg: Boolean; Menssagem: String; Componente: TObject = nil): Boolean;
varAux: TDateTime;
begin
if (TryStrToDate(Data,Aux))then
begin
Result := True
end
else
begin
Result := False;
if (Componente is TWinControl) then
TWinControl(Componente).SetFocus;
if ShowMsg = True then
Application.MessageBox(Pchar(Menssagem), 'Atenção',MB_ICONINFORMATION + MB_OK);
end;
end;
E um exemplo de uso...seria assim..
procedure TForm1.Button1Click(Sender: TObject);
begin
if TValidar.Data(Edit1.Text,true,'Data Inválida',Form1.Edit1) then //Como disse, não precisa instanciar a classe, basta chamar o NomeDaClasse.NomeMétodo.
ShowMessage('Gravar')
else
ShowMessage('Não Gravar');
end;
end.
Mts vezes usar métodos estáticos tbm resolvem nossos problemas....
Espero ter ajudado....flw
GOSTEI 2
Mais Respostas
Marco Salles
12/05/2010
Olhe Rick , acho que dá para melhorar bem sua classe
são vários pontos que apesar da simplicidade da classe pode ser atacado para futuras referencias
por exemplo
vc passa um Componente , para que ele receba o foco
e na implementação do método vc usa o operador Is e seguidamente vc usa o Operador as
A pergunta que lhe faço é ... Pq ao inves de usar o Componente: TObject pq não vc define
Componente: TWincontrol . Assim vc não precisa fazer esta conversão
Uma outra duvida que eu tenho é vc definir uma propriedade cujo controle depende de outros métodos
Por exemplo , algumem que utiliza a sua classe executar
meio sem sentido isto, mas é o que vc fez...
são vários pontos que apesar da simplicidade da classe pode ser atacado para futuras referencias
por exemplo
vc passa um Componente , para que ele receba o foco
function TValidar.CampoObrigatorio(Campo: String; ShowMsg: Boolean; Menssagem: String; Componente: TObject): Boolean;
e na implementação do método vc usa o operador Is e seguidamente vc usa o Operador as
A pergunta que lhe faço é ... Pq ao inves de usar o Componente: TObject pq não vc define
Componente: TWincontrol . Assim vc não precisa fazer esta conversão
Uma outra duvida que eu tenho é vc definir uma propriedade cujo controle depende de outros métodos
Por exemplo , algumem que utiliza a sua classe executar
procedure TForm1.Button1Click(Sender: TObject);
var
validar:TValidar;
begin
validar:=TValidar.Create;
try
if validar.Gravar then
Showmessage('Grava ou Não ???')
else
Showmessage('Pq não Grava');
finally
validar.Free;
end;
end;
meio sem sentido isto, mas é o que vc fez...
GOSTEI 1
Walter Desidera
12/05/2010
Bom dia! Muito obrigado pessoal por disponibilizarem um
pouco do seu tempo para me ajudar... Ainda estou começando... Bem vocês me
deram boas idéias para melhorar a minha classe... Mais a idéia que eu tinha
para esta classe é um pouco diferente da de vocês...
Bem seria assim:
Uma classe que fornece métodos para validação em uma tela de cadastro por
exemplo:
Crio uma instancia e chamo um método qualquer dela, por exemplo:
Esta função devolve um booleano para uma propriedade Gravar, em seguida no
final do código eu apenas testo se essa variável continua True e só assim
efetuo as alterações no banco. Sendo que a property Gravar é Read Only, só os
métodos internos da classe podem alterar e usar este valor...
Programei desta forma porque não queria ficar fazendo if's na implementação dos
métodos; ficando desta forma:
Com métodos estáticos eu tenho que testar com if's se deu certo ou não, com a
property eu não preciso porque ela q verifica se eu posso ou não gravar
as alterações, já que esse valor é retornado a ela quando a função é chamada.
Desse modo posso validar vários campos de uma vez...
Marco você está certo, usar TObject foi um erro, na verdade eu realmente devo
usar TWinControl direto no lugar...
Mais um erro que eu cometi... não crie uma função para abortar caso a property
Gravar seja False, em cada método deveria ter colocado o seguinte código no
inicio:
Assim se uma validação desse errado eu já nem verificaria os outros campos,
evitando várias mensagens uma atrás da outra...
Bem a principio eu realmente queria simplificar ao máximo o uso da classe, por
isso a property gravar também é opcional, é só é usada quando valido vários
campo de uma só vez.. O componente passado como parâmetro também, porque eu
posso validar um valor do banco ou variável que não esteja associada a um
componente...
Bom pessoal, muito obrigado pela ajuda, gostaria de saber se esta minha idéia foi
mal formulada, mais como eu disse anteriormente estou aprendendo... Qualquer
ajuda é muito bem vinda ;)
pouco do seu tempo para me ajudar... Ainda estou começando... Bem vocês me
deram boas idéias para melhorar a minha classe... Mais a idéia que eu tinha
para esta classe é um pouco diferente da de vocês...
Bem seria assim:
Uma classe que fornece métodos para validação em uma tela de cadastro por
exemplo:
Crio uma instancia e chamo um método qualquer dela, por exemplo:
Validar.Data(Edit1.Text,true,'Data Inválida',Form1.Edit1);
Esta função devolve um booleano para uma propriedade Gravar, em seguida no
final do código eu apenas testo se essa variável continua True e só assim
efetuo as alterações no banco. Sendo que a property Gravar é Read Only, só os
métodos internos da classe podem alterar e usar este valor...
Programei desta forma porque não queria ficar fazendo if's na implementação dos
métodos; ficando desta forma:
procedure TForm1.Button1Click(Sender: TObject); var Validar : TValidar; begin Validar := TValidar.Create();
Com métodos estáticos eu tenho que testar com if's se deu certo ou não, com a
property eu não preciso porque ela q verifica se eu posso ou não gravar
as alterações, já que esse valor é retornado a ela quando a função é chamada.
Desse modo posso validar vários campos de uma vez...
Validar.Data(Edit1.Text,true,'Data de Nascimento Inválida',Form1.Edit1); </span>
Validar.Data(Edit2.Text,true,'Data de Cadastro Inválida',Form1.Edit2);
Validar.Data(Edit3.Text,true,'Data LALALA Inválida',Form1.Edit3);
Validar.Data(Edit4.Text,true,'Data BLABLABLA Inválida',Form1.Edit4);
Validar.Data(Edit5.Text,true,'Data TATATA Inválida',Form1.Edit5);</span>
if Validar.Gravar then
ShowMessage('Gravar')
Aqui usei um exemplo de um método simples, não vou chamar nenhuma menssagem aqui,
seria por exemplo um inherited de uma operação de post, caso a
property gravar ainda fosse verdadeira...
FreeAndNil(Validar);
end;
Marco você está certo, usar TObject foi um erro, na verdade eu realmente devo
usar TWinControl direto no lugar...
Mais um erro que eu cometi... não crie uma função para abortar caso a property
Gravar seja False, em cada método deveria ter colocado o seguinte código no
inicio:
if Gravar = False then exit else //Código a Validar
Assim se uma validação desse errado eu já nem verificaria os outros campos,
evitando várias mensagens uma atrás da outra...
Bem a principio eu realmente queria simplificar ao máximo o uso da classe, por
isso a property gravar também é opcional, é só é usada quando valido vários
campo de uma só vez.. O componente passado como parâmetro também, porque eu
posso validar um valor do banco ou variável que não esteja associada a um
componente...
Bom pessoal, muito obrigado pela ajuda, gostaria de saber se esta minha idéia foi
mal formulada, mais como eu disse anteriormente estou aprendendo... Qualquer
ajuda é muito bem vinda ;)
GOSTEI 0
Marco Salles
12/05/2010
Vamos concatenas as Idéas..
Entendi sua intenção..
Esta função devolve um booleano para uma propriedade Gravar, em seguida no final do código eu apenas testo se essa variável continua True e só assim efetuo as alterações no banco. Sendo que a property Gravar é Read Only, só os métodos internos da classe podem alterar e usar este valor...
Mas é muito estranho esta property estar aclopada a outros métodos , além do mais seu raciocineo esta
Errado .. Tente acompanhar
Com métodos estáticos eu tenho que testar com if's se deu certo ou não, com a property eu não preciso porque ela q verifica se eu posso ou não gravar as alterações, já que esse valor é retornado a ela quando a função é chamada. Desse modo posso validar vários campos de uma vez...
Validar.Data(Edit1.Text,true,'Data de Nascimento Inválida',Form1.Edit1); //1
Validar.Data(Edit2.Text,true,'Data de Cadastro Inválida',Form1.Edit2); //2
Validar.Data(Edit3.Text,true,'Data LALALA Inválida',Form1.Edit3); //3
Validar.Data(Edit4.Text,true,'Data BLABLABLA Inválida',Form1.Edit4); //4
Validar.Data(Edit5.Text,true,'Data TATATA Inválida',Form1.Edit5); //45
if Validar.Gravar then
ShowMessage('Gravar')
Suponha que os passos //1 , //2 , //3 , //4 sejam todos Falsos.. Porém o passo //5 Esta tudo Certo
O que que vai acontecer ??? a Propery vai ser True e Vc estar Gravando ... Entende Isto ???
Mesmo que vc Utilize Exit , vc não impede o Compilador de executar as Instruçoes Seguintes
E qual a saida ????
Bem , eu sugiro uma mais orientada a objetos do que este aclopamanento que vc esta fazendo
A Idéia e que ao inves de function estes métodos sejam Procedures e que ao Inves de Retornar
Um boolean , devolvam uma Exceção Não Tratada .. Vc mesmo na sua classe Pode definir uma Exceção
Especifica.. < Ai é uma outra dica Boa e fica o codigobem mais legivel
Ai Vc Varia
try
Validar.Data(Edit1.Text,true,'Data de Nascimento Inválida',Form1.Edit1); //1
Validar.Data(Edit2.Text,true,'Data de Cadastro Inválida',Form1.Edit2); //2
Validar.Data(Edit3.Text,true,'Data LALALA Inválida',Form1.Edit3); //3
Validar.Data(Edit4.Text,true,'Data BLABLABLA Inválida',Form1.Edit4); //4
Validar.Data(Edit5.Text,true,'Data TATATA Inválida',Form1.Edit5); //45
ShowMessage('Gravar')
except
On e:SUAEXCECAO do
begin
ShowMessage('Não foi possivel Gravar')
end;
No fim , gosto muito do método de classes aonde não precisa instanciar a classe , conforme ja foi comentado antes
GOSTEI 0
Walter Desidera
12/05/2010
Marco você está certo novamente, não tinha pensado nisso =/
Neste caso minhas funções não retornam uma Boolean e sim
Procedures com uma Exception (vou pesquisar como fazer isso para tentar fazer
um teste aqui...que eu me lembre era algo como "Raise")
Em suma eu estaria levantando uma Exception caso uma das validações não fosse verdadeira,
caso ela fosse gerada anularia as verificações seguintes definidas dentro do
bloco try...except.
Como as mensagens de erro são tratadas por procedimentos, eu
posso simplesmente não fazer nada quando a exception for levantada, usando ela
apenas para abortar a execução do bloco try...except. Quando ocorresse
qualquer erro na validação, ele nunca chegaria ao método de gravação dos dados,
correto?
EDITADO:
Dei uma olhada e vi que poderia usar uma exception silenciosa sem o Dialog do tipo EAbort:
Assim ainda posso usar um MessageBox normalmente que eu usava para mostrar um erro customizado ao usuário...vou fazer mais alguns testes aqui...
Neste caso minhas funções não retornam uma Boolean e sim
Procedures com uma Exception (vou pesquisar como fazer isso para tentar fazer
um teste aqui...que eu me lembre era algo como "Raise")
Em suma eu estaria levantando uma Exception caso uma das validações não fosse verdadeira,
caso ela fosse gerada anularia as verificações seguintes definidas dentro do
bloco try...except.
Como as mensagens de erro são tratadas por procedimentos, eu
posso simplesmente não fazer nada quando a exception for levantada, usando ela
apenas para abortar a execução do bloco try...except. Quando ocorresse
qualquer erro na validação, ele nunca chegaria ao método de gravação dos dados,
correto?
EDITADO:
Dei uma olhada e vi que poderia usar uma exception silenciosa sem o Dialog do tipo EAbort:
raise EAbort.Create('Data Inválida');
Assim ainda posso usar um MessageBox normalmente que eu usava para mostrar um erro customizado ao usuário...vou fazer mais alguns testes aqui...
GOSTEI 0
Marco Salles
12/05/2010
Simplesmente o Abort seria suficiente
Vc so testaria se a exceção levantada fosse do tipo Abort ( Exceção silenciosa)
Ate um
Try
except
on e:excpetion do // Exceção Mais Geral
//
funcionaria , ja que o Abort tb sera capturado pela classe excpetion
Porém qnd sugeri vc criar ou definir uma exceção especifica para sua classe , fica no meu modo
de ver mais Orientado a Objeto
Tb não esqueça de pesquisar sobre métodos de class , que acho que se enciaxa muito bem neste proposito
Uma outra dica que lhe dou é sobre um braço da POO ... Que diz o seguinte
Toda classe tem uma unica razão de Existir ..ou a lei da Resposanbilidade Unica
Em outras palavras , toda classe deve ter apenas uma única razão para sofre alterações
Não se deve atribuir funçoes para uma classe alem daquela que ela foi projetada . Se uma classe
responsavel por fazer conexão com o banco ela não deve por exemplo executar Sql
entende isto ???
GOSTEI 0
Walter Desidera
12/05/2010
Entendi, seria uma exception customizada própria da
classe... vou ter que dar uma olhada nisso...
Então sobre a responsabilidade única da classe, seria para simplificar o código e eliminar as dependências e acoplamentos de várias funcionalidades para uma mesma classe. Cada classe desempenha um único papel...
Mais uma coisa que estive pensando... Quando defino uma class function ou class procedure eu automaticamente reservei memória as qualquer variáveis que eu venha a usar dentro de minhas funções implementadas na classe, ou seja, automaticamente estou usando memória mesmo que eu não chame nenhuma função da classe...
Seria como uma variável global no Form principal, sempre alocada para uso mesmo que eu não esteja usando...
Se a classe não for estática, essa memória não é reservada, pois seus métodos não estão disponíveis diretamente, a memória só irá ser alocada caso eu crie um objeto desta classe...
Estou certo???
Então sobre a responsabilidade única da classe, seria para simplificar o código e eliminar as dependências e acoplamentos de várias funcionalidades para uma mesma classe. Cada classe desempenha um único papel...
Mais uma coisa que estive pensando... Quando defino uma class function ou class procedure eu automaticamente reservei memória as qualquer variáveis que eu venha a usar dentro de minhas funções implementadas na classe, ou seja, automaticamente estou usando memória mesmo que eu não chame nenhuma função da classe...
Seria como uma variável global no Form principal, sempre alocada para uso mesmo que eu não esteja usando...
Se a classe não for estática, essa memória não é reservada, pois seus métodos não estão disponíveis diretamente, a memória só irá ser alocada caso eu crie um objeto desta classe...
Estou certo???
GOSTEI 0
Marco Salles
12/05/2010
Entendi, seria uma exception customizada própria da classe... vou ter que dar uma olhada nisso...
Isto mesmo
Então sobre a responsabilidade única da classe, seria para simplificar o código....
Cada classe desempenha um único papel...
Isto é um conceito de POO ... Se vc sabe para que serve os bolinhos da classe e se esses bolinhos
estão saindo quimados , então vc modifica , altera , enfim da manuntenção em um lugar especidico
no programa .. E por ai vai todo o conceito de reusabilidade , manuntenção etc e coisa e tal
Mais uma coisa que estive pensando... Quando defino uma class function ou class procedure eu automaticamente reservei memória as qualquer variáveis que eu venha a usar dentro de minhas funções implementadas na classe, ou seja, automaticamente estou usando memória mesmo que eu não chame nenhuma função da classe...
Bem , não tenho conhecimento para dizer que sim nen dizer que não . As biografias que ja li a respeito de
métodos de classe não levantaram nenhuma informação de como é feito este gerenciamento de
memoria no Delphi . O que ela dizem sçao em suma que um método de classe não é especico a nenhum Objeto
da Classe e sim a propria classe ( em outras palavras são metodos Aplicados a classe e não ao Objetos da classe)
Mas não confunda com metodos Estáticos que não tem nada a ver .. Inclusive Metodos de Classe podem Sofrer
Polimorfismo. Apesar de meio abstrato o exemplo abaixo , ele demostar Isto
type
TClasseBase = class
class procedure Mensagem(); virtual;
end;
TClassFilha = class(TClasseBase)
class procedure Mensagem(); Override;
end;
class procedure TClasseBase.Mensagem;
begin
showmessage('Classe Base');
end;
{ TClassFilha }
class procedure TClassFilha.Mensagem;
begin
//inherited;
Showmessage('Classe Filha')
end;
procedure TForm1.Button1Click(Sender: TObject);
var
obj:TClasseBase;
begin
obj:=TClassFilha.Create; //POLIMORFISMO
try
obj.Mensagem;
finally
obj.Free;
end;
end;
Seria ate interresante , definir dois programas com uma certa quantidade de métodos. Um Do modo Tradicional
e outro usando o Metodo de classe , de modo que todos esses metodos em ambos os casos fossem compilados
isto é , lolinhas azuis , ou seja em algum lugar do programa referencia-sse esses métodos. Gera-sse esses dois
executaveis e verificasse o Tamanho do mesmo ... Nunca fiz isto...
GOSTEI 0
Walter Desidera
12/05/2010
Entendi, eu estava confundindo
o tipo dos métodos, acreditava que class methods, por exemplo, não usavam
override...
Sobre a exception eu, andei dando uma pesquisada eu eu teria que criar uma nova
classe descendente da classe Exception (<a href="http://cc.embarcadero.com/item/17819" target="_blank" title="EDN">http://cc.embarcadero.com/item/17819</a>),
para poder ter total liberdade para implementar as menssagens que gostaria que
fossem apresentada, ou seja minha classe TValidar só validariao campo,
TMinhaException faria a parte de tratar a exception.
Tambem achei um jeito de minha idéia anterior funcionar corretamente:
Como minha property FGravar era responssável por verificar se tudo tinha
ocorrido corretamente e então gravaria as informações ficando assim
Não tinha preparado mais já havia solucionado o problema que você tinha me informado
adicionando o Exit sim, pois:
Caso uma função retorne false para FGravar, as outras funções não vão
ser nem testadas, não tem como porque quando uma está errada a condição
Supomos:
Retorna Fgravar como False...
No próximo método...
Não importa se a validação vai dar true ou false, FGravar esta como False, uma
vez False ela não pode se True novamente, só quando uma nova instancia desta
classe for criada, pois a primeira coisa em cada método é verificar se FGravar
está em True para que ele possa validar o próximo campo...
A idéia de uma exception customizada ficaria mais orientada a objeto, mais a
implementação seria mais complexa e um pouco estranha, vamos ver assim:
Ou:
Levanta minmha exception e mostra o que aconteceu e vai direto para o bloco except do try... Mostra a mensagem ("data Inválida"), focus no objeto...
Quando eu entrasse no bloco except do try, aqui não faria simplesmente nada, já
que quando a exception foi levantada ela já tratou o erro, achei que ficou mais
estranho assim...
O Try e uma exception customizada eliminam minha property FGravar, mais ele faz
o mesmo trabalho, ocorreu uma exception, a exception impede a continuidade da
validação e processo de gravação é abortado...
(Não tem nada a ver com o que eu estou fazendo aqui mais achei muito interessante http://www.delphi3000.com/articles/article_3308.asp)
o tipo dos métodos, acreditava que class methods, por exemplo, não usavam
override...
Sobre a exception eu, andei dando uma pesquisada eu eu teria que criar uma nova
classe descendente da classe Exception (<a href="http://cc.embarcadero.com/item/17819" target="_blank" title="EDN">http://cc.embarcadero.com/item/17819</a>),
para poder ter total liberdade para implementar as menssagens que gostaria que
fossem apresentada, ou seja minha classe TValidar só validariao campo,
TMinhaException faria a parte de tratar a exception.
Tambem achei um jeito de minha idéia anterior funcionar corretamente:
Como minha property FGravar era responssável por verificar se tudo tinha
ocorrido corretamente e então gravaria as informações ficando assim
Validar.Data(Edit1.Text,true,'Data de Nascimento Inválida',Form1.Edit1); //False Validar.Data(Edit2.Text,true,'Data de Cadastro Inválida',Form1.Edit2); //False Validar.Data(Edit3.Text,true,'Data LALALA Inválida',Form1.Edit3); //False Validar.Data(Edit4.Text,true,'Data BLABLABLA Inválida',Form1.Edit4); //False Validar.Data(Edit5.Text,true,'Data TATATA Inválida',Form1.Edit5); //True
Não tinha preparado mais já havia solucionado o problema que você tinha me informado
adicionando o Exit sim, pois:
Caso uma função retorne false para FGravar, as outras funções não vão
ser nem testadas, não tem como porque quando uma está errada a condição
Supomos:
Validar.Data(Edit1.Text,true,'Data de Nascimento Inválida',Form1.Edit1); //False
Retorna Fgravar como False...
No próximo método...
Validar.Data(Edit2.Text,true,'Data de Cadastro Inválida',Form1.Edit2);//True
Não importa se a validação vai dar true ou false, FGravar esta como False, uma
vez False ela não pode se True novamente, só quando uma nova instancia desta
classe for criada, pois a primeira coisa em cada método é verificar se FGravar
está em True para que ele possa validar o próximo campo...
Gravar = False then // Condição falsa, não verifica mais nenhum método a seguir destrói o objeto exit else //Código a Validar
A idéia de uma exception customizada ficaria mais orientada a objeto, mais a
implementação seria mais complexa e um pouco estranha, vamos ver assim:
try
Validar.Data(Edit1.Text,true,'Data de Nascimento Inválida',Form1.Edit1); //1
Validar.Data(Edit2.Text,true,'Data de Cadastro Inválida',Form1.Edit2); //2
ShowMessage('Gravar')
except
On e:SUAEXCECAO do
begin
ShowMessage('Não foi possível Gravar')
end;
Ou:
try Validar.Data(Edit1.Text,true,'Data de Nascimento Inválida',Form1.Edit1);
Levanta minmha exception e mostra o que aconteceu e vai direto para o bloco except do try... Mostra a mensagem ("data Inválida"), focus no objeto...
Validar.Data(Edit2.Text,true,'Data de Cadastro Inválida',Form1.Edit2);//2
ShowMessage('Gravar')
except
On e:SUAEXCECAO do
Quando eu entrasse no bloco except do try, aqui não faria simplesmente nada, já
que quando a exception foi levantada ela já tratou o erro, achei que ficou mais
estranho assim...
O Try e uma exception customizada eliminam minha property FGravar, mais ele faz
o mesmo trabalho, ocorreu uma exception, a exception impede a continuidade da
validação e processo de gravação é abortado...
(Não tem nada a ver com o que eu estou fazendo aqui mais achei muito interessante http://www.delphi3000.com/articles/article_3308.asp)
GOSTEI 0
Marco Salles
12/05/2010
Sobre a exception eu, andei dando uma pesquisada eu eu teria que criar uma nova classe descendente da classe Exception (http://cc.embarcadero.com/item/17819), para poder ter total liberdade para implementar as menssagens que gostaria que fossem apresentada, ou seja minha classe TValidar só validariao campo, TMinhaException faria a parte de tratar a exception.
Acho que esta complicando
Antes de proseguir com o exit e com seu raciocineo
teste este exemplo
Defina na sua Classe
type TMinhaExcecao = class(Exception);
Na sua Classe qnd for conveniente , naqueles lugares aonde vc usa a Booleana para dizer que não Pode gravar
Vc Faz
raise TMinhaExcecao.Create('MinhaExcecao');
Com isto esta exceção é levantada e capturada no Bloco Try except do Codigo Principal
procedure TForm1.Button1Click(Sender: TObject);
begin
try
raise TMinhaExcecao.Create('MinhaExcecao');
except
on e:TMinhaExcecao do
Showmessage(e.Message);
on e:exception do
Showmessage('Esta excecao não fio criada') //portanto não sera exceutada
end;
end;
GOSTEI 0
Walter Desidera
12/05/2010
Não entendi muito
bem a sua idéia, vejamos:
//Defini uma nova exception
Num Botão qualquer:
Isso funciona, mesmo que eu chame a exception depois de dar focus e mostrar a minha
menssagem ainda recebo uma menssagem do raise da exception, ou seja duas
menssagens...
Ainda que eu usasse o Abort para ter apenas a minha mensagem , o bloco
try...except é meio estranho, pois quando acontecer uma exceção eu não quero
que ele faça nada...um raise aconteceu ele captura e cai no except
dai no except não faço nada, pq já foi tratado anteriormente no meu método...
Se eu deixa-se apenas com a exception daria certo, mais eliminaria meu
MessageBox...
bem a sua idéia, vejamos:
//Defini uma nova exception
type
TMinhaExcecao = class(Exception);</span><span style="font-size: 10pt;">
class procedure TValidar.CampoObrigatorio(Campo: String; ShowMsg: Boolean;
Menssagem: String; Componente: TWinControl);
begin
if Campo = '' then
begin
//FGravar:= false;
Componente.SetFocus;
if ShowMsg then
Application.MessageBox(Pchar(Menssagem), 'Atenção',MB_ICONINFORMATION + MB_OK);
raise TMinhaExcecao.Create('Campo Obrigatório!');
<== Adicionei a exception criada aqui
end;
end;
Num Botão qualquer:
try
TValidar.CampoObrigatorio(Edit1.Text,True,'Campo Vazio!',Form1.Edit1);
//Aqui a exception foi levantada
except
on e:TMinhaExcecao do //Caindo nesse bloco
Showmessage(e.Message); //Mostrou a mensagem Campo Obrigatório!
on e:exception do
Showmessage('Esta exceção não foi criada') //portanto não sera executada
end;
Isso funciona, mesmo que eu chame a exception depois de dar focus e mostrar a minha
menssagem ainda recebo uma menssagem do raise da exception, ou seja duas
menssagens...
Ainda que eu usasse o Abort para ter apenas a minha mensagem , o bloco
try...except é meio estranho, pois quando acontecer uma exceção eu não quero
que ele faça nada...um raise aconteceu ele captura e cai no except
dai no except não faço nada, pq já foi tratado anteriormente no meu método...
Se eu deixa-se apenas com a exception daria certo, mais eliminaria meu
MessageBox...
GOSTEI 0
Marco Salles
12/05/2010
Não entendi muito bem a sua idéia, vejamos:
entendeu sim,, fez direitinho
Isso funciona, mesmo que eu chame a exception depois de dar focus e mostrar a minha menssagem ainda recebo uma menssagem do raise da exception, ou seja duas menssagens
é so não fazer o Showmessage(e.message)
Try
TValidar(); // e coisa e tal -->> se levantar uma exceção ela sera capturada pelo try except
TValidar(); // e coisa e tal
TValidar(); // e coisa e tal
TValidar(); // e coisa e tal
Showmessage('Gravado')
except
//Não coloque nada Aqui.. A exceção cai neste bloco que não faz nada...
end;
GOSTEI 0
Walter Desidera
12/05/2010
Funcionou perfeitamente kra... Entendi a sua idéia, muito simples e prático =D
Testei desta forma também:
Se deu erro nem valida os outros, e também não recebo um erro do compilador por ter usado um raise... Agora sobre a segurança dessa implementação... Achei uma ótima idéia do try...except é um método mais seguro, um erro ocorre na validação e o processo é abortado imediatamente...
Já a procedure abort tem um código ASM...
Testei desta forma também:
class function TValidar.Data(Data: String; ShowMsg: Boolean; Menssagem: String; Componente: TWinControl = nil): Boolean; var Aux: TDateTime; begin if (TryStrToDate(Data,Aux))then begin Result := True end else begin Result := False; if Componente <> nil then Componente.SetFocus; if ShowMsg = True then Application.MessageBox(Pchar(Menssagem), 'Atenção',MB_ICONINFORMATION + MB_OK); Abort; <=== Ele cancela o processamento dos outros campos também, então não uso o Try...Except end; end; Validar.Data(Edit1.Text,true,'Data Inválida',Form1.Edit1); Aborta e não continua para o próximo Validar.Data(Edit2.Text,true,'Data Inválida',Form1.Edit2);
Se deu erro nem valida os outros, e também não recebo um erro do compilador por ter usado um raise... Agora sobre a segurança dessa implementação... Achei uma ótima idéia do try...except é um método mais seguro, um erro ocorre na validação e o processo é abortado imediatamente...
Já a procedure abort tem um código ASM...
procedure Abort; function ReturnAddr: Pointer; asm MOV EAX,[EBP + 4] end; begin raise EAbort.CreateRes(@SOperationAborted) at ReturnAddr; end; Mais isso é para quando eu tiver mais tempo livre pra entender rsrsrsrs
GOSTEI 0