Padrões de Projeto em C# para Avançados: da Teoria ao Código
\n\nPadrões de projeto não são apenas conceitos abstratos de livros didáticos. Para um desenvolvedor C# experiente, eles se tornam um conjunto de ferramentas que permitem criar uma arquitetura de aplicação flexível, extensível e de fácil manutenção. Neste artigo, abordaremos três padrões poderosos que muitas vezes ficam de fora dos cursos básicos: Visitor, Strategy e Command. Você verá não apenas sua implementação em C#, mas também entenderá como eles resolvem problemas reais no ecossistema .NET.
\n\n1. Padrão Visitor (Visitante) — Trabalhando com Hierarquia de Objetos
\n\nO padrão Visitor permite adicionar novas operações a classes existentes sem modificar sua estrutura. Isso é especialmente útil quando você tem uma hierarquia complexa de objetos e deseja executar diferentes ações dependendo do tipo deles.
\n\nProblema
\nImagine que você tem um sistema de gerenciamento de documentos com as classes TextDocument, Spreadsheet e Presentation. Você precisa adicionar funcionalidade de exportação para PDF, HTML e XML. Sem o padrão Visitor, você teria que modificar cada classe, violando o princípio aberto/fechado (OCP).
Implementação em C#
\n// 1. Interface do elemento\npublic interface IElement\n{\n void Accept(IVisitor visitor);\n}\n\n// 2. Elementos concretos\npublic class TextDocument : IElement\n{\n public string Content { get; set; }\n public void Accept(IVisitor visitor) => visitor.Visit(this);\n}\n\npublic class Spreadsheet : IElement\n{\n public List<List<string>> Rows { get; set; }\n public void Accept(IVisitor visitor) => visitor.Visit(this);\n}\n\n// 3. Interface do visitante\npublic interface IVisitor\n{\n void Visit(TextDocument doc);\n void Visit(Spreadsheet sheet);\n}\n\n// 4. Visitante concreto — exportação para HTML\npublic class HtmlExportVisitor : IVisitor\n{\n public void Visit(TextDocument doc)\n {\n Console.WriteLine($"<h1>{doc.Content}</h1>");\n }\n\n public void Visit(Spreadsheet sheet)\n {\n Console.WriteLine("<table>");\n foreach (var row in sheet.Rows)\n {\n Console.WriteLine("<tr><td>" + string.Join("</td><td>", row) + "</td></tr>");\n }\n Console.WriteLine("</table>");\n }\n}\n\n// Uso\nvar docs = new List<IElement> { new TextDocument { Content = "Olá" }, new Spreadsheet { Rows = new List<List<string>> { new List<string> { "A", "B" } } } };\nvar visitor = new HtmlExportVisitor();\nforeach (var doc in docs) doc.Accept(visitor);\n\nVantagens: fácil adicionar novas operações sem modificar as classes existentes. Desvantagens: se a hierarquia de elementos mudar com frequência, o Visitor se torna inconveniente.
\n\n2. Padrão Strategy (Estratégia) — Troca Dinâmica de Algoritmos
\n\nO padrão Strategy permite definir uma família de algoritmos, encapsular cada um deles e torná-los intercambiáveis. Esta é uma forma clássica de evitar enormes construções if-else ou switch.
Problema
\nVocê precisa implementar um sistema de cálculo de custo de entrega. As formas de entrega são diferentes: por motoboy, pelos correios, retirada no local. Cada forma tem sua própria lógica de cálculo de preço.
\n\nImplementação em C#
\n// 1. Interface da estratégia\npublic interface IShippingStrategy\n{\n decimal CalculateCost(Order order);\n}\n\n// 2. Estratégias concretas\npublic class CourierShipping : IShippingStrategy\n{\n public decimal CalculateCost(Order order) => order.Weight * 5.0m + 100;\n}\n\npublic class PostShipping : IShippingStrategy\n{\n public decimal CalculateCost(Order order) => order.Weight * 2.0m + 50;\n}\n\npublic class PickupShipping : IShippingStrategy\n{\n public decimal CalculateCost(Order