Mudanças entre as edições de "Tiny Types"

De Grupo Acert
Ir para: navegação, pesquisa
 
Linha 2: Linha 2:
  
 
Vamos usar como exemplo códigos fictícios, porém muito comum de encontrar em diversos projetos:
 
Vamos usar como exemplo códigos fictícios, porém muito comum de encontrar em diversos projetos:
−
 
  
 
   TPessoa = class
 
   TPessoa = class
Linha 13: Linha 12:
 
Com essa classe em mãos conseguimos usar o código normalmente.
 
Com essa classe em mãos conseguimos usar o código normalmente.
  
−
 
+
  var
−
var
+
    Pessoa: TPessoa;
−
  Pessoa: TPessoa;
+
  begin
−
begin
+
    // ...
−
  // ...
+
    Pessoa.Nome := 'Tecsystem';
−
  Pessoa.Nome := 'Tecsystem';
+
    Pessoa.CNPJ := '99.999.999/0001-91';
−
  Pessoa.CNPJ := '99.999.999/0001-91';
+
  end;
−
end;
+
  
 
O problema aparece quando queremos adicionar mais utilidade ao codigo, como por exemplo validação, formatação, entre várias outras possibilidades. Nesse caso poderiamos incluir essas utilidades na classe TPessoa, o que tornaria difícil do reuso do código.
 
O problema aparece quando queremos adicionar mais utilidade ao codigo, como por exemplo validação, formatação, entre várias outras possibilidades. Nesse caso poderiamos incluir essas utilidades na classe TPessoa, o que tornaria difícil do reuso do código.
Linha 26: Linha 24:
 
Uma alternativa, que é a mais usada, seria uma classe utilitária onde teremos diversas funções para resolver esses pequenos problemas.
 
Uma alternativa, que é a mais usada, seria uma classe utilitária onde teremos diversas funções para resolver esses pequenos problemas.
  
−
 
+
  TClasseUtils = class
−
TClasseUtils = class
+
  public
−
public
+
    class function ValidaCNPJ(const CNPJ: string): string;
−
  class function ValidaCNPJ(const CNPJ: string): string;
+
    class function GetCNPJFormatado(const CNPJ: string): string;
−
  class function GetCNPJFormatado(const CNPJ: string): string;
+
  end;
−
end;
+
  
  
 
Dessa forma podemos validar o CNPJ em qualquer lugar do sistema, porém criamos dependência dessa TClasseUtils.
 
Dessa forma podemos validar o CNPJ em qualquer lugar do sistema, porém criamos dependência dessa TClasseUtils.
  
−
 
+
  if TClasseUtils.ValidaCNPJ(Pessoa.CNPJ) then
−
if TClasseUtils.ValidaCNPJ(Pessoa.CNPJ) then
+
    // ...
−
  // ...
+
  
 
Usando o Tiny Types
 
Usando o Tiny Types
Linha 44: Linha 40:
 
Uma outra alternativa, que na minha opinião deixa o código mais elegante e expressivo, é através do uso de Tiny Types. Então, que tal isso:
 
Uma outra alternativa, que na minha opinião deixa o código mais elegante e expressivo, é através do uso de Tiny Types. Então, que tal isso:
  
−
 
+
  TPessoaNova = class
−
TPessoaNova = class
+
  public
−
public
+
    property Nome: string read FNome write FNome;
−
  property Nome: string read FNome write FNome;
+
    property CNPJ: TCNPJ read FCNPJ write FCNPJ;
−
  property CNPJ: TCNPJ read FCNPJ write FCNPJ;
+
  end;
−
end;
+
 
−
+
  var
−
var
+
    Pessoa: TPessoaNova;
−
  Pessoa: TPessoaNova;
+
  begin
−
begin
+
    Pessoa.Nome := 'Tecsystem';
−
  Pessoa.Nome := 'Tecsystem';
+
    Pessoa.CNPJ := '99.999.999/0001-91';
−
  Pessoa.CNPJ := '99.999.999/0001-91';
+
    if Pessoa.CNPJ.EhValido() then
−
  if Pessoa.CNPJ.EhValido() then
+
      // ...
−
    // ...
+
  end;
−
end;
+
  
 
Isso pode ser possível através do uso de Tiny Types. O padrão indica o uso de uma classe para resolver o problema, mas o Delphi oferece um tipo de dados mais interessante nesse caso que é o record type. A interface do record seria basicamente isso:
 
Isso pode ser possível através do uso de Tiny Types. O padrão indica o uso de uma classe para resolver o problema, mas o Delphi oferece um tipo de dados mais interessante nesse caso que é o record type. A interface do record seria basicamente isso:
  
−
 
−
TCNPJ = record
 
−
private
 
−
  FValor: string;
 
−
public
 
−
  class operator Implicit(const CNPJ: string): TCNPJ;
 
−
  class operator Implicit(const CNPJ: TCNPJ): string;
 
−
  function EhValido(): Boolean;
 
−
  // ...
 
−
end;
 
−
 
−
A implementação é normal, com exceção do operator overloading class operator implicit que resolve um erro em tempo de compilação ao tentar atribuir um valor a uma property do tipo record.
 
−
 
−
Segue abaixo a unit de exemplo com o código completo das funcionalidades para consulta:
 
−
 
−
unit DocsBR;
 
−
 
−
interface
 
−
 
−
type
 
  
 
   TCNPJ = record
 
   TCNPJ = record
 
   private
 
   private
−
     FUnformatted: string;
+
     FValor: string;
−
    function GetFormatted: string;
+
−
 
+
 
   public
 
   public
 
     class operator Implicit(const CNPJ: string): TCNPJ;
 
     class operator Implicit(const CNPJ: string): TCNPJ;
 
     class operator Implicit(const CNPJ: TCNPJ): string;
 
     class operator Implicit(const CNPJ: TCNPJ): string;
 +
    function EhValido(): Boolean;
 +
    // ...
 +
  end;
  
−
    function IsValid(): Boolean;
+
A implementação é normal, com exceção do operator overloading class operator implicit que resolve um erro em tempo de compilação ao tentar atribuir um valor a uma property do tipo record.
  
−
    property Unformatted: string read FUnformatted;
+
Segue abaixo a unit de exemplo com o código completo das funcionalidades para consulta:
−
    property Formatted: string read GetFormatted;
+
  
 +
  unit DocsBR;
 +
 
 +
  interface
 +
 
 +
  type
 +
 
 +
    TCNPJ = record
 +
    private
 +
      FUnformatted: string;
 +
      function GetFormatted: string;
 +
 
 +
    public
 +
      class operator Implicit(const CNPJ: string): TCNPJ;
 +
      class operator Implicit(const CNPJ: TCNPJ): string;
 +
 
 +
      function IsValid(): Boolean;
 +
 
 +
      property Unformatted: string read FUnformatted;
 +
      property Formatted: string read GetFormatted;
 +
 
 +
    end;
 +
 
 +
    TCPF = record
 +
    private
 +
      FUnformatted: string;
 +
 
 +
      function GetFormatted: string;
 +
     
 +
    public
 +
      class operator Implicit(const CPF: string): TCPF;
 +
      class operator Implicit(const CPF: TCPF): string;
 +
 
 +
      function IsValid(): Boolean;
 +
 
 +
      property Unformatted: string read FUnformatted;
 +
      property Formatted: string read GetFormatted;
 +
 
 +
    end;
 +
 
 +
  implementation
 +
 
 +
  uses
 +
    MaskUtils, StrUtils, SysUtils;
 +
 
 +
  function Clear(const Doc: string): string;
 +
  var
 +
    Letter: Char;
 +
  begin
 +
 
 +
    Result := '';
 +
 
 +
    for Letter in Doc do
 +
    begin
 +
 
 +
      if Letter in ['0'..'9'] then
 +
        Result := Result + Letter;
 +
 
 +
    end;
 +
 
 
   end;
 
   end;
−
 
−
  TCPF = record
 
−
  private
 
−
    FUnformatted: string;
 
 
    
 
    
−
    function GetFormatted: string;
+
  { TCNPJ }
−
   public
+
    
−
    class operator Implicit(const CPF: string): TCPF;
+
  class operator TCNPJ.Implicit(const CNPJ: string): TCNPJ;
−
     class operator Implicit(const CPF: TCPF): string;
+
  begin
−
 
+
     Result.FUnformatted := Clear(CNPJ);
−
    function IsValid(): Boolean;
+
−
 
+
−
    property Unformatted: string read FUnformatted;
+
−
    property Formatted: string read GetFormatted;
+
−
 
+
 
   end;
 
   end;
−
 
+
 
−
implementation
+
   function TCNPJ.GetFormatted: string;
−
 
+
−
uses
+
−
   MaskUtils, StrUtils, SysUtils;
+
−
 
+
−
function Clear(const Doc: string): string;
+
−
var
+
−
  Letter: Char;
+
−
begin
+
−
 
+
−
  Result := '';
+
−
 
+
−
  for Letter in Doc do
+
 
   begin
 
   begin
−
 
+
     Result := MaskUtils.FormatMaskText('00.000.000/0000-00;0; ', FUnformatted);
−
     if Letter in ['0'..'9'] then
+
−
      Result := Result + Letter;
+
−
 
+
 
   end;
 
   end;
−
 
−
end;
 
−
 
−
{ TCNPJ }
 
−
 
−
class operator TCNPJ.Implicit(const CNPJ: string): TCNPJ;
 
−
begin
 
−
 
−
  Result.FUnformatted := Clear(CNPJ);
 
−
 
−
end;
 
−
 
−
function TCNPJ.GetFormatted: string;
 
−
begin
 
−
 
−
  Result := MaskUtils.FormatMaskText('00.000.000/0000-00;0; ', FUnformatted);
 
−
 
−
end;
 
−
 
−
class operator TCNPJ.Implicit(const CNPJ: TCNPJ): string;
 
−
begin
 
−
 
−
  Result := CNPJ.FUnformatted;
 
−
 
−
end;
 
−
 
−
function TCNPJ.IsValid: Boolean;
 
−
const
 
−
  BLACKLIST: array[0..9] of string = ('00000000000000',
 
−
                                      '11111111111111',
 
−
                                      '22222222222222',
 
−
                                      '33333333333333',
 
−
                                      '44444444444444',
 
−
                                      '55555555555555',
 
−
                                      '66666666666666',
 
−
                                      '77777777777777',
 
−
                                      '88888888888888',
 
−
                                      '99999999999999');
 
−
var
 
−
  IsInvalidSize: Boolean;
 
−
  IsBlacklisted: Boolean;
 
−
  I: Integer;
 
−
  D1, D2: Integer;
 
−
begin
 
 
    
 
    
−
   IsInvalidSize := Length(FUnformatted) <> 14;
+
   class operator TCNPJ.Implicit(const CNPJ: TCNPJ): string;
−
  IsBlacklisted := AnsiIndexStr(FUnformatted, BLACKLIST) >= 0;
+
−
  if IsInvalidSize or IsBlacklisted then
+
 
   begin
 
   begin
−
     Result := False;
+
     Result := CNPJ.FUnformatted;
−
   end
+
   end;
−
   else
+
    
 +
  function TCNPJ.IsValid: Boolean;
 +
  const
 +
    BLACKLIST: array[0..9] of string = ('00000000000000',
 +
                                        '11111111111111',
 +
                                        '22222222222222',
 +
                                        '33333333333333',
 +
                                        '44444444444444',
 +
                                        '55555555555555',
 +
                                        '66666666666666',
 +
                                        '77777777777777',
 +
                                        '88888888888888',
 +
                                        '99999999999999');
 +
  var
 +
    IsInvalidSize: Boolean;
 +
    IsBlacklisted: Boolean;
 +
    I: Integer;
 +
    D1, D2: Integer;
 
   begin
 
   begin
−
 
+
   
−
     D1 := 0;
+
     IsInvalidSize := Length(FUnformatted) <> 14;
−
 
+
     IsBlacklisted := AnsiIndexStr(FUnformatted, BLACKLIST) >= 0;
−
     for I := 1 to 12 do
+
   
 +
    if IsInvalidSize or IsBlacklisted then
 
     begin
 
     begin
−
 
+
       Result := False;
−
       if I < 5 then
+
     end
−
        D1 := D1 + (StrToInt(FUnformatted[I]) * (6 - I))
+
    else
−
      else
+
     begin
−
        D1 := D1 + (StrToInt(FUnformatted[I]) * (14 - I));
+
 
−
 
+
−
     end;
+
−
 
+
−
     D1 := 11 - (D1 mod 11);
+
−
 
+
−
    if D1 >= 10 then
+
 
       D1 := 0;
 
       D1 := 0;
−
   
+
 
−
    D2:= D1 * 2;
+
      for I := 1 to 12 do
−
    for I := 1 to 12 do
+
      begin
−
    begin
+
 
−
 
+
        if I < 5 then
−
      if I < 6 then
+
          D1 := D1 + (StrToInt(FUnformatted[I]) * (6 - I))
−
        D2 := D2 + (StrToInt(FUnformatted[I]) * (7 - I))
+
        else
−
      else
+
          D1 := D1 + (StrToInt(FUnformatted[I]) * (14 - I));
−
        D2 := D2 + (StrToInt(FUnformatted[I]) * (15 - I));
+
 
−
 
+
      end;
 +
 
 +
      D1 := 11 - (D1 mod 11);
 +
 
 +
      if D1 >= 10 then
 +
        D1 := 0;
 +
     
 +
      D2:= D1 * 2;
 +
     
 +
      for I := 1 to 12 do
 +
      begin
 +
       
 +
        if I < 6 then
 +
          D2 := D2 + (StrToInt(FUnformatted[I]) * (7 - I))
 +
        else
 +
          D2 := D2 + (StrToInt(FUnformatted[I]) * (15 - I));
 +
         
 +
      end;
 +
     
 +
      D2 := 11 - (D2 mod 11);
 +
     
 +
      if D2 >= 10 then D2 :=0;
 +
     
 +
      Result := (IntToStr(D1) + IntToStr(D2)) = Copy(FUnformatted, 13, 2);
 +
     
 
     end;
 
     end;
−
 
−
    D2 := 11 - (D2 mod 11);
 
 
      
 
      
−
    if D2 >= 10 then D2 :=0;
 
−
 
−
    Result := (IntToStr(D1) + IntToStr(D2)) = Copy(FUnformatted, 13, 2);
 
−
 
 
   end;
 
   end;
−
 
−
end;
 
−
 
−
{ TCPF }
 
−
class operator TCPF.Implicit(const CPF: string): TCPF;
 
−
begin
 
−
 
−
  Result.FUnformatted := Clear(CPF);
 
−
 
−
end;
 
−
 
−
function TCPF.GetFormatted: string;
 
−
begin
 
−
 
−
  Result := MaskUtils.FormatMaskText('000.000.000-00;0; ', FUnformatted);
 
−
 
−
end;
 
−
 
−
class operator TCPF.Implicit(const CPF: TCPF): string;
 
−
begin
 
−
 
−
  Result := CPF.FUnformatted;
 
−
 
−
end;
 
−
 
−
function TCPF.IsValid: Boolean;
 
−
const
 
−
  BLACKLIST: array[0..9] of string = ('00000000000',
 
−
                                      '11111111111',
 
−
                                      '22222222222',
 
−
                                      '33333333333',
 
−
                                      '44444444444',
 
−
                                      '55555555555',
 
−
                                      '66666666666',
 
−
                                      '77777777777',
 
−
                                      '88888888888',
 
−
                                      '99999999999');
 
−
var
 
−
  IsInvalidSize: Boolean;
 
−
  IsBlacklisted: Boolean;
 
−
  I: Integer;
 
−
  D1, D2: Integer;
 
−
begin
 
 
    
 
    
−
   IsInvalidSize := Length(FUnformatted) <> 11;
+
   { TCPF }
−
   IsBlacklisted := AnsiIndexStr(FUnformatted, BLACKLIST) >= 0;
+
  class operator TCPF.Implicit(const CPF: string): TCPF;
 +
   begin
 +
    Result.FUnformatted := Clear(CPF);
 +
  end;
 
    
 
    
−
   if IsInvalidSize or IsBlacklisted then
+
   function TCPF.GetFormatted: string;
 
   begin
 
   begin
−
     Result := False;
+
     Result := MaskUtils.FormatMaskText('000.000.000-00;0; ', FUnformatted);
−
   end
+
   end;
−
   else
+
    
 +
  class operator TCPF.Implicit(const CPF: TCPF): string;
 
   begin
 
   begin
−
 
+
    Result := CPF.FUnformatted;
−
     D1 := 0;
+
  end;
−
 
+
 
−
     for I := 1 to 9 do
+
  function TCPF.IsValid: Boolean;
−
      D1 := D1 + (StrToInt(FUnformatted[I]) * (11 - I));
+
  const
 +
    BLACKLIST: array[0..9] of string = ('00000000000',
 +
                                        '11111111111',
 +
                                        '22222222222',
 +
                                        '33333333333',
 +
                                        '44444444444',
 +
                                        '55555555555',
 +
                                        '66666666666',
 +
                                        '77777777777',
 +
                                        '88888888888',
 +
                                        '99999999999');
 +
  var
 +
    IsInvalidSize: Boolean;
 +
    IsBlacklisted: Boolean;
 +
    I: Integer;
 +
     D1, D2: Integer;
 +
  begin
 +
 
 +
    IsInvalidSize := Length(FUnformatted) <> 11;
 +
    IsBlacklisted := AnsiIndexStr(FUnformatted, BLACKLIST) >= 0;
 +
 
 +
     if IsInvalidSize or IsBlacklisted then
 +
    begin
 +
      Result := False;
 +
    end
 +
    else
 +
    begin
 +
 
 +
      D1 := 0;
 +
 
 +
      for I := 1 to 9 do
 +
        D1 := D1 + (StrToInt(FUnformatted[I]) * (11 - I));
 
      
 
      
−
    D1 := 11 - (D1 mod 11);
+
      D1 := 11 - (D1 mod 11);
 
      
 
      
−
    if D1 >= 10 then
+
      if D1 >= 10 then
−
 
+
 
−
    D1 := 0;
+
      D1 := 0;
 
      
 
      
−
    D2 := D1 * 2;
+
      D2 := D1 * 2;
 
      
 
      
−
    for I := 1 to 9 do
+
      for I := 1 to 9 do
−
      D2 := D2 + (StrToInt(FUnformatted[I]) * (12 - I));
+
        D2 := D2 + (StrToInt(FUnformatted[I]) * (12 - I));
−
 
+
 
−
    D2 := 11 - (D2 mod 11);
+
      D2 := 11 - (D2 mod 11);
 
      
 
      
−
    if D2 >= 10 then
+
      if D2 >= 10 then
−
      D2 :=0;
+
        D2 :=0;
−
 
+
 
−
    Result := (IntToStr(D1) + IntToStr(D2)) = Copy(FUnformatted, 10, 2);
+
      Result := (IntToStr(D1) + IntToStr(D2)) = Copy(FUnformatted, 10, 2);
−
 
+
 
 +
    end;
 +
 
 
   end;
 
   end;
−
 
+
 
−
end;
+
  end.
−
 
+
−
end.
+

Edição atual tal como às 10h13min de 7 de janeiro de 2015