Generics são um poderoso recurso introduzido no Delphi a partir da versão 2009, permitindo que desenvolvedores criem classes, métodos e tipos parametrizados que promovem segurança de tipo e reutilização de código. Esse paradigma é amplamente utilizado em linguagens modernas e oferece uma alternativa robusta à prática de usar tipos universais como TObject
, que podem resultar em verificações manuais e erros em tempo de execução.
Ao usar generics, o programador pode criar estruturas altamente flexíveis e tipadas, sem sacrificar o desempenho ou a integridade do código. Classes genéricas, por exemplo, permitem que tipos específicos sejam definidos apenas no momento da utilização, tornando o código mais legível, eficiente e seguro.
Neste artigo, abordaremos o conceito de generics no Delphi, com exemplos práticos de como criar e manipular listas genéricas e classes parametrizadas. Para ilustrar, desenvolveremos uma classe genérica que manipula listas de objetos, mostrando como trabalhar com elementos de forma segura e escalável.
Vamos explorar como implementar generics no Delphi, seus benefícios e as melhores práticas para evitar armadilhas comuns.
O que são Generics no Delphi?
Generics permitem que você declare classes, interfaces, métodos e tipos parametrizados. Eles são definidos por placeholders para tipos que são concretizados em tempo de compilação.
A sintaxe básica para definir uma classe genérica no Delphi é:
1 2 3 4 5 6 7 8 9 10 |
type TMinhaClasseGenerica<T> = class private FDado: T; public procedure SetDado(const Value: T); function GetDado: T; end; |
Nesse exemplo, T
é um parâmetro de tipo que pode ser substituído por qualquer tipo concreto, como Integer
, String
, ou até mesmo outra classe.
Exemplo Prático: Classe Genérica para Manipulação de Listas
Criemos uma classe genérica que atua como uma lista para armazenar elementos de tipos variados. Essa classe incluirá métodos para adicionar, remover e listar os elementos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
type TListaGenerica<T> = class private FItens: TList<T>; public constructor Create; destructor Destroy; override; procedure Adicionar(const Item: T); procedure Remover(const Item: T); function ObterTodos: TArray<T>; end; { TListaGenerica } constructor TListaGenerica<T>.Create; begin inherited; FItens := TList<T>.Create; end; destructor TListaGenerica<T>.Destroy; begin FItens.Free; inherited; end; procedure TListaGenerica<T>.Adicionar(const Item: T); begin FItens.Add(Item); end; procedure TListaGenerica<T>.Remover(const Item: T); begin FItens.Remove(Item); end; function TListaGenerica<T>.ObterTodos: TArray<T>; begin Result := FItens.ToArray; end; |
Como Usar a Classe Genérica
A seguir, um exemplo de como usar essa classe genérica para manipular uma lista de strings:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
procedure TestarGenerics; var Lista: TListaGenerica<String>; begin Lista := TListaGenerica<String>.Create; try Lista.Adicionar('Delphi'); Lista.Adicionar('Generics'); Lista.Remover('Delphi'); var Itens: TArray<String> := Lista.ObterTodos; for var Item in Itens do Writeln(Item); finally Lista.Free; end; end; |
Benefícios do Uso de Generics
- Segurança de Tipo: Erros de tipos são detectados em tempo de compilação, reduzindo falhas em tempo de execução.
- Reutilização de Código: Classes e métodos genéricos podem ser usados com qualquer tipo, eliminando a necessidade de duplicar lógica.
- Performance: Como a substituição do tipo ocorre em tempo de compilação, não há impacto no desempenho em tempo de execução.
Boas Práticas
- Sempre nomeie seus parâmetros de tipo de maneira clara, como
T
,TKey
,TValue
, para melhorar a legibilidade. - Evite a criação de classes genéricas muito complexas, pois podem dificultar a manutenção do código.
- Utilize métodos e propriedades bem definidos para encapsular a lógica.
Exemplo Prático: Sistema de Emissão de Notas Fiscais Eletrônicas
Estrutura do Sistema
- Classe genérica para manipulação de listas de objetos relacionados à nota fiscal.
- Classes específicas para o cabeçalho e os itens da nota fiscal.
- Uso das classes genéricas para organizar os dados.
Definindo as Classes
1. Classe TNotaFiscalCabecalho
Representa o cabeçalho da nota fiscal, contendo informações como número, data e cliente.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
type TNotaFiscalCabecalho = class private FNumero: Integer; FData: TDateTime; FCliente: String; public property Numero: Integer read FNumero write FNumero; property Data: TDateTime read FData write FData; property Cliente: String read FCliente write FCliente; end; |
2. Classe TNotaFiscalItem
Representa os itens da nota fiscal, contendo descrição, quantidade e valor unitário.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
type TNotaFiscalItem = class private FDescricao: String; FQuantidade: Double; FValorUnitario: Currency; public property Descricao: String read FDescricao write FDescricao; property Quantidade: Double read FQuantidade write FQuantidade; property ValorUnitario: Currency read FValorUnitario write FValorUnitario; function ValorTotal: Currency; end; { TNotaFiscalItem } function TNotaFiscalItem.ValorTotal: Currency; begin Result := FQuantidade * FValorUnitario; end; |
3. Classe Genérica TListaNotaFiscal
Utilizada para manipular listas de cabeçalhos ou itens.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
type TListaNotaFiscal<T> = class private FItens: TList<T>; public constructor Create; destructor Destroy; override; procedure Adicionar(const Item: T); function ObterTodos: TArray<T>; end; { TListaNotaFiscal } constructor TListaNotaFiscal<T>.Create; begin inherited; FItens := TList<T>.Create; end; destructor TListaNotaFiscal<T>.Destroy; begin FItens.Free; inherited; end; procedure TListaNotaFiscal<T>.Adicionar(const Item: T); begin FItens.Add(Item); end; function TListaNotaFiscal<T>.ObterTodos: TArray<T>; begin Result := FItens.ToArray; end; |
Usando as Classes no Sistema de Emissão
Exemplo de como criar um cabeçalho e adicionar itens à nota fiscal:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
procedure EmitirNotaFiscal; var Cabecalho: TNotaFiscalCabecalho; Item: TNotaFiscalItem; ListaItens: TListaNotaFiscal<TNotaFiscalItem>; begin // Criando o cabeçalho da nota fiscal Cabecalho := TNotaFiscalCabecalho.Create; try Cabecalho.Numero := 12345; Cabecalho.Data := Now; Cabecalho.Cliente := 'Cliente Exemplo'; // Criando a lista de itens ListaItens := TListaNotaFiscal<TNotaFiscalItem>.Create; try // Adicionando itens à nota fiscal Item := TNotaFiscalItem.Create; Item.Descricao := 'Produto A'; Item.Quantidade := 10; Item.ValorUnitario := 50.00; ListaItens.Adicionar(Item); Item := TNotaFiscalItem.Create; Item.Descricao := 'Produto B'; Item.Quantidade := 5; Item.ValorUnitario := 100.00; ListaItens.Adicionar(Item); // Exibindo os itens for Item in ListaItens.ObterTodos do Writeln(Format('%s: %.2f x %.2f = %.2f', [Item.Descricao, Item.Quantidade, Item.ValorUnitario, Item.ValorTotal])); finally ListaItens.Free; end; finally Cabecalho.Free; end; end; |
Saída Esperada
1 2 3 4 |
Produto A: 10.00 x 50.00 = 500.00 Produto B: 5.00 x 100.00 = 500.00 |
Benefícios do Uso de Generics no Exemplo
- Flexibilidade: A classe genérica
TListaNotaFiscal<T>
pode ser reutilizada tanto para o cabeçalho quanto para os itens. - Segurança de Tipo: Garante que somente objetos do tipo especificado sejam adicionados à lista.
- Manutenibilidade: Adicionar novos tipos relacionados à nota fiscal será mais simples e organizado.
Participe da Comunidade no Telegram
🚀 Quer continuar essa discussão e trocar ideias com outros desenvolvedores? Junte-se à nossa comunidade no Telegram! Lá, você pode comentar sobre o que achou deste artigo, tirar suas dúvidas e compartilhar suas experiências com Delphi e ainda discutir ou tirar suas dúvidas sobre os mais variados temas em uma comunidade com mais de 1.000 desenvolvedores.
🔗 Clique aqui para entrar na comunidade
Te vejo lá!
Conclusão
Generics são uma ferramenta poderosa no Delphi, permitindo que desenvolvedores criem soluções mais flexíveis, reutilizáveis e seguras. No exemplo apresentado, vimos como utilizar generics para estruturar um sistema de emissão de notas fiscais, aplicando conceitos avançados para manipulação de dados de forma eficiente.
A classe genérica TListaNotaFiscal<T>
demonstrou como podemos criar listas tipadas, adaptáveis a diferentes tipos de dados, enquanto as classes TNotaFiscalCabecalho
e TNotaFiscalItem
mostraram como encapsular informações relevantes em estruturas bem definidas.
Ao usar generics, desenvolvedores podem reduzir duplicação de código, aumentar a clareza e evitar erros comuns relacionados à manipulação de tipos. Apesar de serem um recurso avançado, com prática e aplicação cuidadosa, eles podem transformar a forma como projetos Delphi são desenvolvidos, especialmente em sistemas complexos e escaláveis.
Se você deseja explorar mais sobre generics ou outros recursos avançados do Delphi, temas como interfaces genéricas, constrangimentos de tipos e funções anônimas parametrizadas são ótimos próximos passos.
Adriano Santos