{"id":934,"date":"2024-12-16T06:00:00","date_gmt":"2024-12-16T09:00:00","guid":{"rendered":"https:\/\/adrianosantostreina.com.br\/blog\/?p=934"},"modified":"2024-12-23T12:37:20","modified_gmt":"2024-12-23T15:37:20","slug":"fluent-interface-com-generics-em-delphi","status":"publish","type":"post","link":"https:\/\/adrianosantostreina.com.br\/blog\/fluent-interface-com-generics-em-delphi\/","title":{"rendered":"Fluent Interface com Generics em Delphi"},"content":{"rendered":"\n<p>Interfaces fluentes s\u00e3o uma abordagem poderosa para simplificar a intera\u00e7\u00e3o com objetos em linguagens de programa\u00e7\u00e3o. Baseada no conceito de encadeamento de m\u00e9todos, essa t\u00e9cnica busca tornar o c\u00f3digo mais leg\u00edvel e expressivo, eliminando a necessidade de intermedi\u00e1rios desnecess\u00e1rios ao configurar ou manipular objetos.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>No Delphi, combinar a abordagem de Fluent Interface com Generics oferece um ganho significativo em flexibilidade e reutiliza\u00e7\u00e3o. Generics permitem trabalhar com tipos parametrizados, eliminando a rigidez de tipos est\u00e1ticos e proporcionando solu\u00e7\u00f5es adapt\u00e1veis.<\/p>\n\n\n\n<p>Imagine uma estrutura que manipule listas gen\u00e9ricas, permitindo opera\u00e7\u00f5es como adi\u00e7\u00e3o, remo\u00e7\u00e3o, ordena\u00e7\u00e3o e busca, tudo em um \u00fanico encadeamento de chamadas. Este artigo explora como implementar essa funcionalidade em Delphi, respeitando princ\u00edpios de Clean Code e boas pr\u00e1ticas recomendadas, como as Normas de Codifica\u00e7\u00e3o j\u00e1 citadas aqui nesse blog.<\/p>\n\n\n\n<p><strong>Prepara\u00e7\u00e3o e Cen\u00e1rio<\/strong><br>Antes de mergulharmos na implementa\u00e7\u00e3o, garantiremos que o conceito esteja claro. Se voc\u00ea j\u00e1 utiliza Generics e m\u00e9todos fluentes, esta abordagem ampliar\u00e1 seu dom\u00ednio, mostrando como uni-los eficientemente para criar sistemas elegantes e robustos.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Fluent Interface com Generics em Delphi<\/strong><\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>O que s\u00e3o Fluent Interfaces?<\/strong><\/h4>\n\n\n\n<p>Fluent Interface \u00e9 um padr\u00e3o de design comportamental que permite o encadeamento de m\u00e9todos em chamadas sequenciais. Seu principal objetivo \u00e9 melhorar a legibilidade e reduzir a complexidade ao lidar com APIs ou objetos complexos.<\/p>\n\n\n\n<p>No contexto do Delphi, m\u00e9todos fluentes geralmente retornam a pr\u00f3pria inst\u00e2ncia do objeto (<code>Self<\/code>) ap\u00f3s cada chamada, permitindo que opera\u00e7\u00f5es subsequentes sejam executadas diretamente no mesmo objeto.<\/p>\n\n\n\n<p>Um exemplo simples de uma Fluent Interface seria uma classe de builder:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >TBuilder = class\npublic\n  function SetName(const AName: string): TBuilder;\n  function SetAge(const AAge: Integer): TBuilder;\n  function Build: TObject;\nend;\n<\/pre><\/div>\n\n\n\n<p>O encadeamento ocorre ao retornar <code>Self<\/code>:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >TBuilder.Create\n  .SetName('Jo\u00e3o')\n  .SetAge(30)\n  .Build;\n<\/pre><\/div>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>O papel dos Generics<\/strong><\/h4>\n\n\n\n<p>Generics s\u00e3o uma funcionalidade que permite criar classes e m\u00e9todos parametrizados por tipos. Eles aumentam a flexibilidade do c\u00f3digo ao eliminar a necessidade de criar v\u00e1rias implementa\u00e7\u00f5es para diferentes tipos.<\/p>\n\n\n\n<p>Em Delphi, Generics s\u00e3o definidos usando a sintaxe <code>&lt;T&gt;<\/code> para classes, m\u00e9todos ou at\u00e9 mesmo interfaces:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >TGenericList&lt;T&gt; = class\nprivate\n  FItems: TArray&lt;T&gt;;\npublic\n  procedure Add(const Item: T);\n  function Get(Index: Integer): T;\nend;\n<\/pre><\/div>\n\n\n\n<p>Ao utilizar Generics, uma mesma classe pode operar com qualquer tipo, desde inteiros at\u00e9 classes complexas:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >var\n  List: TGenericList&lt;Integer&gt;;\nbegin\n  List := TGenericList&lt;Integer&gt;.Create;\n  List.Add(10);\nend;\n<\/pre><\/div>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Unindo Fluent Interfaces e Generics<\/strong><\/h4>\n\n\n\n<p>A combina\u00e7\u00e3o de Fluent Interfaces com Generics possibilita o desenvolvimento de estruturas extremamente poderosas e reutiliz\u00e1veis. Vamos criar uma classe que implemente uma lista gen\u00e9rica com m\u00e9todos fluentes para:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Adicionar elementos \u00e0 lista.<\/li>\n\n\n\n<li>Remover elementos.<\/li>\n\n\n\n<li>Ordenar os itens.<\/li>\n\n\n\n<li>Buscar elementos.<\/li>\n<\/ul>\n\n\n\n<p>Al\u00e9m disso, o c\u00f3digo seguir\u00e1 pr\u00e1ticas como:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Respeitar margens e indenta\u00e7\u00e3o, conforme as Normas de Codifica\u00e7\u00e3o.<\/li>\n\n\n\n<li>Nomenclatura clara para m\u00e9todos e par\u00e2metros, usando Pascal Case e prefixos.<\/li>\n\n\n\n<li>Modularidade para evitar m\u00e9todos monol\u00edticos.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Implementa\u00e7\u00e3o da Estrutura Fluente com Generics<\/strong><\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Estrutura da Classe Base<\/strong><\/h4>\n\n\n\n<p>Come\u00e7aremos criando a classe <code>TFluentList&lt;T&gt;<\/code>, que ser\u00e1 respons\u00e1vel por armazenar os elementos em uma lista gen\u00e9rica e oferecer m\u00e9todos fluentes.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >unit FluentList;\n\ninterface\n\nuses\n  System.Generics.Collections, System.SysUtils;\n\ntype\n  TFluentList&lt;T&gt; = class\n  private\n    FItems: TList&lt;T&gt;;\n  public\n    constructor Create;\n    destructor Destroy; override;\n\n    function Add(const AItem: T): TFluentList&lt;T&gt;;\n    function Remove(const AItem: T): TFluentList&lt;T&gt;;\n    function Sort(Comparison: TComparison&lt;T&gt;): TFluentList&lt;T&gt;;\n    function Find(const Predicate: TFunc&lt;T, Boolean&gt;): T;\n\n    function Items: TArray&lt;T&gt;;\n  end;\n\nimplementation\n\n{ TFluentList&lt;T&gt; }\n\nconstructor TFluentList&lt;T&gt;.Create;\nbegin\n  inherited;\n  FItems := TList&lt;T&gt;.Create;\nend;\n\ndestructor TFluentList&lt;T&gt;.Destroy;\nbegin\n  FItems.Free;\n  inherited;\nend;\n\nfunction TFluentList&lt;T&gt;.Add(const AItem: T): TFluentList&lt;T&gt;;\nbegin\n  FItems.Add(AItem);\n  Result := Self; \/\/ Retorna a pr\u00f3pria inst\u00e2ncia\nend;\n\nfunction TFluentList&lt;T&gt;.Remove(const AItem: T): TFluentList&lt;T&gt;;\nbegin\n  FItems.Remove(AItem);\n  Result := Self;\nend;\n\nfunction TFluentList&lt;T&gt;.Sort(Comparison: TComparison&lt;T&gt;): TFluentList&lt;T&gt;;\nbegin\n  FItems.Sort(TComparer&lt;T&gt;.Construct(Comparison));\n  Result := Self;\nend;\n\nfunction TFluentList&lt;T&gt;.Find(const Predicate: TFunc&lt;T, Boolean&gt;): T;\nvar\n  Item: T;\nbegin\n  for Item in FItems do\n    if Predicate(Item) then\n      Exit(Item);\n  Result := Default(T);\nend;\n\nfunction TFluentList&lt;T&gt;.Items: TArray&lt;T&gt;;\nbegin\n  Result := FItems.ToArray;\nend;\n\nend.\n<\/pre><\/div>\n\n\n\n<p><strong>Detalhamento dos M\u00e9todos<\/strong><\/p>\n\n\n\n<p>1. <strong><code>Add<\/code><\/strong>:<br>Adiciona um item \u00e0 lista e retorna a inst\u00e2ncia da classe (<code>Self<\/code>), permitindo o encadeamento.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >function TFluentList&lt;T&gt;.Add(const AItem: T): TFluentList&lt;T&gt;;\nbegin\n  FItems.Add(AItem);\n  Result := Self;\nend;\n<\/pre><\/div>\n\n\n\n<p>2. <strong><code>Remove<\/code><\/strong>:<br>Remove um item espec\u00edfico da lista usando o m\u00e9todo padr\u00e3o <code>Remove<\/code> do <code>TList&lt;T><\/code>.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >function TFluentList&lt;T&gt;.Remove(const AItem: T): TFluentList&lt;T&gt;;\nbegin\n  FItems.Remove(AItem);\n  Result := Self;\nend;\n<\/pre><\/div>\n\n\n\n<p>3. <strong><code>Sort<\/code><\/strong>:<br>Ordena a lista usando uma fun\u00e7\u00e3o de compara\u00e7\u00e3o passada como par\u00e2metro.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >function TFluentList&lt;T&gt;.Sort(Comparison: TComparison&lt;T&gt;): TFluentList&lt;T&gt;;\nbegin\n  FItems.Sort(TComparer&lt;T&gt;.Construct(Comparison));\n  Result := Self;\nend;\n<\/pre><\/div>\n\n\n\n<p>4. <strong><code>Find<\/code><\/strong>:<br>Realiza uma busca na lista com base em uma fun\u00e7\u00e3o de predicado, retornando o primeiro item que atender ao crit\u00e9rio.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >function TFluentList&lt;T&gt;.Find(const Predicate: TFunc&lt;T, Boolean&gt;): T;\nvar\n  Item: T;\nbegin\n  for Item in FItems do\n    if Predicate(Item) then\n      Exit(Item);\n  Result := Default(T);\nend;\n<\/pre><\/div>\n\n\n\n<p>5. <strong><code>Items<\/code><\/strong>:<br>Retorna todos os itens da lista como um array, sem modificar o estado da classe.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >uses\n  FluentList, System.SysUtils;\n\ntype\n  TPerson = record\n    Name: string;\n    Age: Integer;\n  end;\n\nvar\n  List: TFluentList&lt;TPerson&gt;;\n  Found: TPerson;\nbegin\n  List := TFluentList&lt;TPerson&gt;.Create;\n  try\n    List.Add(TPerson.Create('Alice', 30))\n        .Add(TPerson.Create('Bob', 25))\n        .Add(TPerson.Create('Charlie', 35))\n        .Sort(\n          function(const A, B: TPerson): Integer\n          begin\n            Result := CompareText(A.Name, B.Name);\n          end\n        );\n\n    Found := List.Find(\n      function(const Person: TPerson): Boolean\n      begin\n        Result := Person.Name = 'Alice';\n      end\n    );\n\n    WriteLn(Format('Found: %s, Age: %d', [Found.Name, Found.Age]));\n\n    \/\/ Exibe todos os itens da lista\n    for var Person in List.Items do\n      WriteLn(Format('%s, %d', [Person.Name, Person.Age]));\n  finally\n    List.Free;\n  end;\nend;\n<\/pre><\/div>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Explica\u00e7\u00e3o do Exemplo<\/strong><\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Adi\u00e7\u00e3o<\/strong>: Usamos o m\u00e9todo <code>Add<\/code> para incluir tr\u00eas registros na lista.<\/li>\n\n\n\n<li><strong>Ordena\u00e7\u00e3o<\/strong>: O m\u00e9todo <code>Sort<\/code> organiza a lista por nome, utilizando <code>CompareText<\/code> para compara\u00e7\u00e3o.<\/li>\n\n\n\n<li><strong>Busca<\/strong>: <code>Find<\/code> localiza o registro cujo nome \u00e9 &#8220;Alice&#8221;.<\/li>\n\n\n\n<li><strong>Itera\u00e7\u00e3o<\/strong>: O m\u00e9todo <code>Items<\/code> retorna todos os itens, permitindo iterar sobre eles.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Participe da Comunidade no Telegram<\/h3>\n\n\n\n<p>\ud83d\ude80 Quer continuar essa discuss\u00e3o e trocar ideias com outros desenvolvedores? Junte-se \u00e0 nossa comunidade no Telegram! L\u00e1, voc\u00ea pode comentar sobre o que achou deste artigo, tirar suas d\u00favidas e compartilhar suas experi\u00eancias com Delphi e ainda discutir ou tirar suas d\u00favidas sobre os mais variados temas em uma comunidade com mais de 1.000 desenvolvedores.<\/p>\n\n\n\n<p>\ud83d\udd17 <a href=\"https:\/\/t.me\/AdrianoSantosCommunity\" target=\"_blank\" rel=\"noreferrer noopener\">Clique aqui para entrar na comunidade<\/a><\/p>\n\n\n\n<p>Te vejo l\u00e1!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Conclus\u00e3o<\/strong><\/h3>\n\n\n\n<p>A combina\u00e7\u00e3o de Fluent Interfaces com Generics em Delphi proporciona uma abordagem eficiente e elegante para manipula\u00e7\u00e3o de objetos, tornando o c\u00f3digo mais leg\u00edvel, flex\u00edvel e adapt\u00e1vel. O exemplo apresentado mostra como implementar uma estrutura fluente que opera sobre listas gen\u00e9ricas, com m\u00e9todos para adicionar, remover, ordenar e buscar itens de forma encadeada.<\/p>\n\n\n\n<p>Ao adotar essa t\u00e9cnica, voc\u00ea melhora a expressividade de suas APIs, facilita a manuten\u00e7\u00e3o e aumenta a reutiliza\u00e7\u00e3o de c\u00f3digo. A utiliza\u00e7\u00e3o de boas pr\u00e1ticas, como nomes significativos, modularidade e clareza, garante que a implementa\u00e7\u00e3o atenda aos padr\u00f5es de qualidade esperados em projetos modernos.<\/p>\n\n\n\n<p><strong>Gostou do conte\u00fado?<\/strong> Considere aplicar essa t\u00e9cnica em seus projetos e explorar outras combina\u00e7\u00f5es com Generics para criar solu\u00e7\u00f5es ainda mais robustas.<\/p>\n\n\n\n<p>Adriano Santos<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Interfaces fluentes s\u00e3o uma abordagem poderosa para simplificar a intera\u00e7\u00e3o com objetos em linguagens de programa\u00e7\u00e3o. Baseada no conceito de encadeamento de m\u00e9todos, essa t\u00e9cnica busca tornar o c\u00f3digo mais leg\u00edvel e expressivo, eliminando a necessidade de intermedi\u00e1rios desnecess\u00e1rios ao configurar ou manipular objetos.<\/p>\n","protected":false},"author":1,"featured_media":936,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-934","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog"],"_links":{"self":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts\/934","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/comments?post=934"}],"version-history":[{"count":2,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts\/934\/revisions"}],"predecessor-version":[{"id":937,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts\/934\/revisions\/937"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/media\/936"}],"wp:attachment":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/media?parent=934"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/categories?post=934"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/tags?post=934"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}