Olá galera, nesta Quick Tips irei mostrar um dos padrões de projetos mais utilizados hoje em dia no desenvolvimento de Software: o padrão Singleton.

Com o Singleton podemos ter a certeza de que só existirá um único objeto instanciado para determinada classe. Um exemplo seria o usuário conectado ao sistema ou até mesmo a conexão direta ao banco de dados.

Vou criar uma unit e seu nome será uUsuario. Nela implementaremos uma série de configurações dentro de uma classe chamada TUsuario.

Ao criar uma unit vamos declarar a mesma da seguinte forma, e salvar como uUsuario:


unit uUsuario;
interface
uses
    uDM, DB, SqlExpr, SysUtils, Dialogs, IdHashMessageDigest;
type
 
TUsuario = class
Private
   { Objetivo : Podemos notar que existem fields/variáveis Class Var, estes 
    são necessários que configuremos desta forma, para podermos armazenar o 
    conteúdo do usuário ao ser localizado na base de dados, quando usamos um 
    método de Class, para acessarmos Fields dentro dele, só podemos acessar 
    quando estes são de Class também }
    class var FID: Integer;
    class var FSenha: String;
    class var FNivel: Integer;
    class var FUsuario: String;
    class var FInstance: TUsuario;
    constructor CreatePrivate;
    constructor Create;
 
    { private declarations }
    protected
    { protected declarations }
    public
    { public declarations }
    
   { Objetivo : Efetuar o login a uma base de dados passando usuário e senha, 
    além da conexão ao qual se deseja conectar  }
    class function Login(AUsuario, ASenha: String;xConexao: TSQLConnection): 
    Boolean;
   { Objetivo : alterar a senha de um usuário logado por exemplo }
    class function ChangePassword(strOldPassword, trNewPassword,strCheckPassword: 
                  String; xConexao : TSQLConnection):Boolean;
   { Objetivo : Obter a instancia caso exista, ou criar a mesma, apenas uma única vez }
    class function GetInstance: TUsuario;
 
   { Objetivo : Função criada em outro artigo, serve para podermos criptografar uma 
    string utilizando Hash MD5, observe que demos uses em IdHashMessageDigest }
    class function Criptografar(const Value: string): string; static;
 
   { Objetivo : Função para retornar o nome do usuário logado }
    class function GetUsuarioLogado: String;
   { Objetivo : Propriedades de configuração da minha tabela de usuário, configure e 
    altere de acordo com a sua necessidade }
    class property ID: Integer read FID;
    class property Usuario: String read FUsuario;
    class property Senha: String read FSenha;
    class property Nivel: Integer read FNivel;
end;

Agora iremos mostrar a implementação dos métodos declarados:


class function TUsuario.Criptografar(const Value: string): string;
var
    xMD5: TIdHashMessageDigest5;
begin
    xMD5 := TIdHashMessageDigest5.Create;
    try
        Result := xMD5.HashStringAsHex(Value);
    finally
        xMD5.Free;
    end;
end;
 
class function TUsuario.ChangePassword(strOldPassword,
strNewPassword, strCheckPassword: String; xConexao : TSQLConnection): Boolean;
var
    xQry : TSQLQuery;
begin
    xQry := TSQLQuery.Create(Nil);
    xQry.SQLConnection := xConexao;
    if FSenha = Criptografar(strOldPassword) then
    begin
        if strNewPassword = strCheckPassword then
        begin
            try
                xQry.SQL.Add('UPDATE USUARIO SET SENHA =     
                '+QuotedStr(Criptografar(strNewPassword))+
                ' WHERE IDUSUARIO = '+ IntToStr(FID));
                xQry.ExecSQL;
                Result := True;
                FSenha := Criptografar(strNewPassword);
                MessageDlg('Senha alterada com sucesso !!!!',
                mtInformation,[mbOK],0);
            finally
                FreeAndNil(xQry);
            end;
        end
        else
            MessageDlg('As senhas não conferem !!!!',
            mtInformation,[mbOK],0);
   end
   else
      MessageDlg('A senha antiga não confere !!!!',
      mtInformation,[mbOK],0);
   end;
 
constructor TUsuario.Create;
begin
     raise Exception.Create('Para obter uma instância de TUsuario utilize     
        TUsuario.GetInstance !');
end;
 
constructor TUsuario.CreatePrivate;
begin
   inherited Create;
end;
 
class function TUsuario.GetInstance: TUsuario;
begin
   if not Assigned(FInstance) then
      FInstance := TUsuario.CreatePrivate;
   Result := FInstance;
end;
 
class function TUsuario.GetUsuarioLogado: String;
begin
   Result := FUsuario;
end;
 
class function TUsuario.Login(AUsuario, ASenha: String; xConexao: 
TSQLConnection): Boolean;
var
   xQry : TSQLQuery;
begin
   try
      xry := TSQLQuery.Create(Nil);
      xQry.SQLConnection := xConexao;
      xQry.SQL.Add('SELECT * FROM USUARIO WHERE DESCRICAO =       
      '+QuotedStr(AUsuario)+
      ' AND SENHA = '+QuotedStr(Criptografar(ASenha)));
      xQry.Open;
      if not xQry.IsEmpty then
      begin
         FID := xQry.Fields[0].AsInteger;
         FUsuario := xQry.Fields[1].AsString;
         FSenha := xQry.Fields[2].AsString;
         FNivel := xQry.Fields[3].AsInteger;
         Result := True;
   end
   else
      ShowMessage('Usuario ou senha inválidos');
 
   except
      on E : EXCEPTION do
            raise Exception.Create('ERRO NAO ESPERADO '+ 
            E.Message +#13+
            E.ClassName + ' - - - ' + E.UnitName);
    end;
end;
end.

O que é interessante nestes métodos, é que podemos aproveitá-los para outros projetos, montados nesta uUsuario.pas.

Agora irei mostrar como usar os métodos implementados anteriormente na unit uUsuario.pas. Veja como é simples a implementação da mesma.

  • Login: monte uma tela basicamente com dois Edits(EdtUsuario,EdtSenha) e dois BitBtn(BtnAcessar,BtnSenha), além de uma Progressbar (apenas de enfeite).
    tela de login
    Figura 1. Tela de login
    
    procedure TFrmLogin.BtnAcessarClick(Sender: TObject);
    var
       I: Integer;
    begin
       BtnAcessar.Enabled := False;
       { Obs: Veja que estou passando uma Conexão, esta é do tipo 
        TSQLConnection}
       if TUsuario.GetInstance.Login(EdtUsuario.Text, 
       EdtSenha.Text, DM.Conexao ) then
       begin
           ProgressBar1.Max := 100;
           for I := 0 to 100 - 1 do
           begin
               ProgressBar1.Position := I;
               Sleep(5);
               Application.ProcessMessages;
           end;
       Close;
       ModalResult := MrOk;
       end;
       BtnAcessar.Enabled := True;
    end;
  • GetUsuarioLogado: este é bem simples, onde uma function resulta uma string. Podemos colocar, por exemplo, em uma StatusBar.
    
    procedure TFrmLogin.BtnAcessarClick(Sender: TObject);
     begin
         StatusBar1.Panels[0].Text := TUsuario.GetUsuarioLogado;
         { Obs: Como os métodos são de Classe, podemos pegar os 
          mesmos também da seguinte forma}
         StatusBar1.Panels[1].Text := TUsuario.Usuario;
         StatusBar1.Panels[2].Text := TUsuario.Nivel;
     end;
  • ChangePassword: monte uma tela basicamente com quatro Edits(EdtUsuario,EdtSenha, EdtNovaSenha, EdtConfirmaSenha), dois BitBtn(BtnMudar,BtnSenha) uma dica de layout.
    nova tela
    Figura 2. Tela de mudar senha
    
    procedure TFrmMudarSenha.btnMudarClick(Sender: TObject);
    begin
               TUsuario.GetInstance.ChangePassword(EdtSenha.Text,
                           EdtNovaSenha.Text,
                           EdtConfirmaSenha.Text,
                           DM.Conexao);
               Close;
    end;
    
    procedure TFrmMudarSenha.FormShow(Sender: TObject);
    begin
       { Obs: Fiz com que ao abrir a tela para mudar a senha, o usuário 
        já seja carregado no EdtUsuario}
               EdtUsuario.Text := TUsuario.GetUsuarioLogado;
    end;

Fico por aqui ate à próxima Quick Tips.