Exibir código-fonte para Tiny Types
Ir para:
navegação
,
pesquisa
'''Tiny Types''' é um padrão que basicamente propõe encapsular tipos simples dentro classes específicas de domínio. Parece simples, mas o uso de Tiny Types, além de proporcionar o enriquecimento do domain model, favorece a manutenibilidade e legibilidade do código. Vamos usar como exemplo códigos fictícios, porém muito comum de encontrar em diversos projetos: TPessoa = class public property Nome: string read FNome write FNome; property CNPJ: string read FCNPJ write FCNPJ; // ... end; Com essa classe em mãos conseguimos usar o código normalmente. var Pessoa: TPessoa; begin // ... Pessoa.Nome := 'Tecsystem'; Pessoa.CNPJ := '99.999.999/0001-91'; 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. Uma alternativa, que é a mais usada, seria uma classe utilitária onde teremos diversas funções para resolver esses pequenos problemas. TClasseUtils = class public class function ValidaCNPJ(const CNPJ: string): string; class function GetCNPJFormatado(const CNPJ: string): string; end; Dessa forma podemos validar o CNPJ em qualquer lugar do sistema, porém criamos dependência dessa TClasseUtils. if TClasseUtils.ValidaCNPJ(Pessoa.CNPJ) then // ... Usando o Tiny Types 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 public property Nome: string read FNome write FNome; property CNPJ: TCNPJ read FCNPJ write FCNPJ; end; var Pessoa: TPessoaNova; begin Pessoa.Nome := 'Tecsystem'; Pessoa.CNPJ := '99.999.999/0001-91'; if Pessoa.CNPJ.EhValido() then // ... 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: 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 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; { 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; IsBlacklisted := AnsiIndexStr(FUnformatted, BLACKLIST) >= 0; if IsInvalidSize or IsBlacklisted then begin Result := False; end else begin D1 := 0; for I := 1 to 12 do begin if I < 5 then D1 := D1 + (StrToInt(FUnformatted[I]) * (6 - I)) else D1 := D1 + (StrToInt(FUnformatted[I]) * (14 - 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; { 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; 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); if D1 >= 10 then D1 := 0; D2 := D1 * 2; for I := 1 to 9 do D2 := D2 + (StrToInt(FUnformatted[I]) * (12 - I)); D2 := 11 - (D2 mod 11); if D2 >= 10 then D2 :=0; Result := (IntToStr(D1) + IntToStr(D2)) = Copy(FUnformatted, 10, 2); end; end; end.
Retornar para
Tiny Types
.
Menu de navegação
Ferramentas pessoais
Criar conta
Autenticar-se
Espaços nominais
Página
Discussão
Variantes
Visualizações
Ler
Ver código-fonte
Ver histórico
Ações
Pesquisar
Navegação
Página principal
Mudanças recentes
Página aleatória
Ferramentas
Páginas afluentes
Alterações relacionadas
Páginas especiais
Informações da página