{"id":1037,"date":"2026-03-19T16:59:07","date_gmt":"2026-03-19T19:59:07","guid":{"rendered":"https:\/\/adrianosantostreina.com.br\/blog\/?p=1037"},"modified":"2026-03-19T16:59:07","modified_gmt":"2026-03-19T19:59:07","slug":"padroes-projeto-delphi-factory-method-strategy","status":"publish","type":"post","link":"https:\/\/adrianosantostreina.com.br\/blog\/padroes-projeto-delphi-factory-method-strategy\/","title":{"rendered":"Padr\u00f5es de Projeto em Delphi: Factory Method e Strategy com Boas Pr\u00e1ticas"},"content":{"rendered":"<div style=\"max-width: 900px; margin: auto; font-family: Arial,Helvetica,sans-serif; color: #1f2937; line-height: 1.6;\">\n<h1>Padr\u00f5es de Projeto em Delphi: Factory Method e Strategy com Boas Pr\u00e1ticas<\/h1>\n<h2>Introdu\u00e7\u00e3o<\/h2>\n<p>Este artigo apresenta uma abordagem pr\u00e1tica e detalhada sobre a aplica\u00e7\u00e3o dos padr\u00f5es de projeto Factory Method e Strategy em Delphi, enfatizando princ\u00edpios de Programa\u00e7\u00e3o Orientada a Objetos (POO) e pr\u00e1ticas de Clean Code. Forne\u00e7o exemplos completos de c\u00f3digo (unidades e uso) que compilam em vers\u00f5es modernas do Delphi, explicando decis\u00f5es de projeto, gerenciamento de mem\u00f3ria e como integrar esses padr\u00f5es em aplica\u00e7\u00f5es reais. O foco \u00e9 apresentar alternativas limpas, f\u00e1ceis de testar e extens\u00edveis, respeitando a regra de declarar m\u00e9todos que ser\u00e3o sobrescritos como <code>virtual<\/code> na classe base e utilizando construtores\/destrutores adequados.<\/p>\n<h2>Vis\u00e3o Geral dos Padr\u00f5es<\/h2>\n<p>Os padr\u00f5es de projeto ajudam a resolver problemas recorrentes de desenho de software. O <strong>Factory Method<\/strong> delega a cria\u00e7\u00e3o de objetos a subclasses, permitindo escolher o tipo concreto em tempo de execu\u00e7\u00e3o. O <strong>Strategy<\/strong> encapsula algoritmos intercambi\u00e1veis por meio de composi\u00e7\u00e3o, facilitando trocar comportamento sem alterar a estrutura cliente.<\/p>\n<h3>Por que usar esses padr\u00f5es em Delphi?<\/h3>\n<p>Delphi, sendo fortemente orientado a objetos, favorece a utiliza\u00e7\u00e3o de padr\u00f5es para criar c\u00f3digo mais test\u00e1vel, modular e de f\u00e1cil manuten\u00e7\u00e3o. Ao aplicar Factory Method e Strategy voc\u00ea obt\u00e9m desacoplamento e melhor ader\u00eancia ao princ\u00edpio Open\/Closed (aberto para extens\u00e3o, fechado para modifica\u00e7\u00e3o).<\/p>\n<h2>Factory Method em Delphi<\/h2>\n<p>Nesta se\u00e7\u00e3o descrevo o padr\u00e3o, a estrutura t\u00edpica e um exemplo completo: uma f\u00e1brica de loggers que retorna diferentes implementa\u00e7\u00f5es de TLogger. A classe base declara o m\u00e9todo f\u00e1brica como <code>virtual<\/code> e as subclasses o <code>override<\/code>.<\/p>\n<h3>Estrutura e responsabilidades<\/h3>\n<p>A classe abstrata de f\u00e1brica define a assinatura do m\u00e9todo criador (por exemplo, <code>CreateLogger<\/code>), enquanto subclasses concretas instanciam objetos concretos (p.ex., <code>TConsoleLogger<\/code> ou <code>TFileLogger<\/code>).<\/p>\n<h3>Exemplo de implementa\u00e7\u00e3o (unidade: LoggerFactory.pas)<\/h3>\n<pre><code>unit LoggerFactory;\n\ninterface\n\nuses\n  SysUtils, Classes;\n\ntype\n  \/\/ Classe base de logger: m\u00e9todos que ser\u00e3o sobrescritos s\u00e3o abstract virtual\n  TLogger = class\n  public\n    procedure Log(const AMsg: string); virtual; abstract;\n  end;\n\n  \/\/ Implementa\u00e7\u00e3o concreta: console\n  TConsoleLogger = class(TLogger)\n  public\n    procedure Log(const AMsg: string); override;\n  end;\n\n  \/\/ Implementa\u00e7\u00e3o concreta: arquivo\n  TFileLogger = class(TLogger)\n  private\n    FFileName: string;\n  public\n    constructor Create(const AFileName: string);\n    destructor Destroy; override;\n    procedure Log(const AMsg: string); override;\n  end;\n\n  \/\/ F\u00e1brica abstrata: m\u00e9todo f\u00e1brica declarado virtual\n  TLoggerFactory = class\n  public\n    function CreateLogger: TLogger; virtual; abstract;\n  end;\n\n  \/\/ F\u00e1bricas concretas\n  TConsoleLoggerFactory = class(TLoggerFactory)\n  public\n    function CreateLogger: TLogger; override;\n  end;\n\n  TFileLoggerFactory = class(TLoggerFactory)\n  private\n    FFileName: string;\n  public\n    constructor Create(const AFileName: string);\n    destructor Destroy; override;\n    function CreateLogger: TLogger; override;\n  end;\n\nimplementation\n\n{ TConsoleLogger }\nprocedure TConsoleLogger.Log(const AMsg: string);\nbegin\n  Writeln(Format('CONSOLE: %s', [AMsg]));\nend;\n\n{ TFileLogger }\nconstructor TFileLogger.Create(const AFileName: string);\nbegin\n  inherited Create;\n  FFileName := AFileName;\nend;\n\ndestructor TFileLogger.Destroy;\nbegin\n  inherited;\nend;\n\nprocedure TFileLogger.Log(const AMsg: string);\nvar\n  SL: TStringList;\nbegin\n  SL := TStringList.Create;\n  try\n    if FileExists(FFileName) then\n      SL.LoadFromFile(FFileName);\n    SL.Add(AMsg);\n    SL.SaveToFile(FFileName);\n  finally\n    SL.Free;\n  end;\nend;\n\n{ TConsoleLoggerFactory }\nfunction TConsoleLoggerFactory.CreateLogger: TLogger;\nbegin\n  Result := TConsoleLogger.Create;\nend;\n\n{ TFileLoggerFactory }\nconstructor TFileLoggerFactory.Create(const AFileName: string);\nbegin\n  inherited Create;\n  FFileName := AFileName;\nend;\n\ndestructor TFileLoggerFactory.Destroy;\nbegin\n  inherited;\nend;\n\nfunction TFileLoggerFactory.CreateLogger: TLogger;\nbegin\n  Result := TFileLogger.Create(FFileName);\nend;\n\nend.<\/code><\/pre>\n<h3>Exemplo de uso<\/h3>\n<p>Utilize a f\u00e1brica para obter o logger sem acoplar o c\u00f3digo cliente \u00e0s classes concretas:<\/p>\n<pre><code>var\n  Factory: TLoggerFactory;\n  Logger: TLogger;\nbegin\n  \/\/ Exemplo com console\n  Factory := TConsoleLoggerFactory.Create;\n  try\n    Logger := Factory.CreateLogger;\n    try\n      Logger.Log('Teste no console');\n    finally\n      Logger.Free;\n    end;\n  finally\n    Factory.Free;\n  end;\n\n  \/\/ Exemplo com arquivo\n  Factory := TFileLoggerFactory.Create('log.txt');\n  try\n    Logger := Factory.CreateLogger;\n    try\n      Logger.Log('Teste em arquivo');\n    finally\n      Logger.Free;\n    end;\n  finally\n    Factory.Free;\n  end;<\/code><\/pre>\n<h2>Strategy em Delphi<\/h2>\n<p>Strategy permite trocar algoritmos em tempo de execu\u00e7\u00e3o. Implementaremos uma estrat\u00e9gia de compress\u00e3o simples com uma vers\u00e3o sem compress\u00e3o e um esqueleto para compress\u00e3o real (integr\u00e1vel com bibliotecas de compress\u00e3o).<\/p>\n<h3>Estrutura e responsabilidades<\/h3>\n<p>Uma classe abstrata define a interface do algoritmo (<code>Compress<\/code>), subclasses implementam diferentes algoritmos e um contexto (<code>TCompressor<\/code>) mant\u00e9m e usa a estrat\u00e9gia atual.<\/p>\n<h3>Exemplo de implementa\u00e7\u00e3o (unidade: CompressionStrategy.pas)<\/h3>\n<pre><code>unit CompressionStrategy;\n\ninterface\n\nuses\n  SysUtils, Classes;\n\ntype\n  TCompressionStrategy = class\n  public\n    function Compress(const AData: TBytes): TBytes; virtual; abstract;\n  end;\n\n  \/\/ Estrat\u00e9gia sem compress\u00e3o (pass-through)\n  TNoCompressionStrategy = class(TCompressionStrategy)\n  public\n    function Compress(const AData: TBytes): TBytes; override;\n  end;\n\n  \/\/ Estrat\u00e9gia de compress\u00e3o (esqueleto)\n  TZCompressionStrategy = class(TCompressionStrategy)\n  public\n    function Compress(const AData: TBytes): TBytes; override;\n  end;\n\n  \/\/ Contexto que usa uma estrat\u00e9gia\n  TCompressor = class\n  private\n    FStrategy: TCompressionStrategy;\n    procedure SetStrategy(const Value: TCompressionStrategy);\n  public\n    constructor Create(AStrategy: TCompressionStrategy);\n    destructor Destroy; override;\n    function CompressData(const AData: TBytes): TBytes;\n    property Strategy: TCompressionStrategy read FStrategy write SetStrategy;\n  end;\n\nimplementation\n\n{ TNoCompressionStrategy }\nfunction TNoCompressionStrategy.Compress(const AData: TBytes): TBytes;\nbegin\n  Result := AData;\nend;\n\n{ TZCompressionStrategy }\nfunction TZCompressionStrategy.Compress(const AData: TBytes): TBytes;\nbegin\n  \/\/ Implementa\u00e7\u00e3o de exemplo: retorno vazio como placeholder.\n  \/\/ Para compress\u00e3o real, integre ZLib ou outras bibliotecas.\n  SetLength(Result, 0);\nend;\n\n{ TCompressor }\nconstructor TCompressor.Create(AStrategy: TCompressionStrategy);\nbegin\n  inherited Create;\n  FStrategy := AStrategy;\nend;\n\ndestructor TCompressor.Destroy;\nbegin\n  FStrategy.Free;\n  inherited;\nend;\n\nprocedure TCompressor.SetStrategy(const Value: TCompressionStrategy);\nbegin\n  if FStrategy &lt;&gt; Value then\n  begin\n    FStrategy.Free;\n    FStrategy := Value;\n  end;\nend;\n\nfunction TCompressor.CompressData(const AData: TBytes): TBytes;\nbegin\n  if Assigned(FStrategy) then\n    Result := FStrategy.Compress(AData)\n  else\n    Result := AData;\nend;\n\nend.<\/code><\/pre>\n<h3>Exemplo de uso<\/h3>\n<p>Crie o contexto com a estrat\u00e9gia desejada e altere em tempo de execu\u00e7\u00e3o, se necess\u00e1rio:<\/p>\n<pre><code>var\n  Compressor: TCompressor;\n  Data, OutData: TBytes;\nbegin\n  Data := TEncoding.UTF8.GetBytes('Exemplo de dados');\n  Compressor := TCompressor.Create(TNoCompressionStrategy.Create);\n  try\n    OutData := Compressor.CompressData(Data);\n    \/\/ Trocar para outra estrat\u00e9gia em tempo de execu\u00e7\u00e3o\n    Compressor.Strategy := TZCompressionStrategy.Create;\n    OutData := Compressor.CompressData(Data);\n  finally\n    Compressor.Free;\n  end;<\/code><\/pre>\n<h2>Boas pr\u00e1ticas e observa\u00e7\u00f5es<\/h2>\n<p>Seguindo Clean Code: escolha nomes claros (TLogger, CreateLogger, CompressData), mantenha fun\u00e7\u00f5es curtas, evite efeitos colaterais e gerencie posse de mem\u00f3ria. Em Delphi, padronize a posse (quem cria \u00e9 respons\u00e1vel por liberar) e documente contratos de responsabilidade (quem libera objetos).<\/p>\n<h3>Testabilidade e extens\u00e3o<\/h3>\n<p>Ambos os padr\u00f5es facilitam inje\u00e7\u00e3o de depend\u00eancia e testes unit\u00e1rios: voc\u00ea pode passar f\u00e1bricas ou estrat\u00e9gias mockadas para o c\u00f3digo cliente e validar comportamentos espec\u00edficos sem alterar c\u00f3digo de produ\u00e7\u00e3o.<\/p>\n<h3>#Dica do Mestre<\/h3>\n<p>Se precisar de compress\u00e3o real, integre a biblioteca adequada (por exemplo ZLib). ZLib n\u00e3o \u00e9 o foco deste artigo, mas \u00e9 uma biblioteca C amplamente usada para compress\u00e3o: veja https:\/\/en.wikipedia.org\/wiki\/Zlib. Consulte tamb\u00e9m o DocWiki da Embarcadero para refer\u00eancias sobre bibliotecas do Delphi: https:\/\/docwiki.embarcadero.com\/.<\/p>\n<h2>Recursos e refer\u00eancias<\/h2>\n<p>Recomendo a leitura de:<\/p>\n<ul>\n<li>DocWiki da Embarcadero: https:\/\/docwiki.embarcadero.com\/ (documenta\u00e7\u00e3o e exemplos oficiais).<\/li>\n<li>Clean Code \u2014 princ\u00edpios e pr\u00e1ticas de Robert C. Martin (aplicados aqui como orienta\u00e7\u00e3o de nomes e simplicidade).<\/li>\n<\/ul>\n<h2>Conclus\u00e3o<\/h2>\n<p>Factory Method e Strategy s\u00e3o padr\u00f5es poderosos que, quando aplicados corretamente em Delphi, promovem um projeto desacoplado, extens\u00edvel e test\u00e1vel. Este artigo apresentou implementa\u00e7\u00f5es pr\u00e1ticas e seguras, com aten\u00e7\u00e3o especial a declara\u00e7\u00f5es <code>virtual<\/code>\/<code>override<\/code>, gerenciamento de mem\u00f3ria e clareza de c\u00f3digo. Comece integrando pequenas f\u00e1bricas e estrat\u00e9gias em \u00e1reas cr\u00edticas da sua aplica\u00e7\u00e3o e evolua conforme a necessidade.<\/p>\n<hr \/>\n<p style=\"font-size: 0.85rem; color: #6b7280;\">Notas: exemplos escritos para compila\u00e7\u00e3o em vers\u00f5es modernas do Delphi. Ajustes m\u00ednimos podem ser necess\u00e1rios conforme a plataforma e a RTL. Pratique boas normas de codifica\u00e7\u00e3o e siga as diretrizes locais do seu projeto.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Padr\u00f5es de Projeto em Delphi: Factory Method e Strategy com Boas Pr\u00e1ticas Introdu\u00e7\u00e3o Este artigo apresenta uma abordagem pr\u00e1tica e detalhada sobre a aplica\u00e7\u00e3o dos padr\u00f5es de projeto Factory Method e Strategy em Delphi, enfatizando princ\u00edpios de Programa\u00e7\u00e3o Orientada a Objetos (POO) e pr\u00e1ticas de Clean Code. Forne\u00e7o exemplos completos de c\u00f3digo (unidades e uso) [&hellip;]<\/p>\n","protected":false},"author":59,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1037","post","type-post","status-publish","format-standard","hentry","category-blog"],"_links":{"self":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts\/1037","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\/59"}],"replies":[{"embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/comments?post=1037"}],"version-history":[{"count":1,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts\/1037\/revisions"}],"predecessor-version":[{"id":1043,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts\/1037\/revisions\/1043"}],"wp:attachment":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/media?parent=1037"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/categories?post=1037"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/tags?post=1037"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}