Appearance
Exemplos de Design Patterns em C#
Este projeto contém exemplos simples e práticos dos principais Design Patterns utilizados em C#.
1. Singleton
Garante que uma classe tenha apenas uma instância e fornece um ponto global de acesso a ela.
csharp
public class Logger
{
private static Logger _instance;
public static Logger Instance => _instance ??= new Logger();
private Logger() { }
public void Log(string message) => Console.WriteLine(message);
}2. Repository
Abstrai a lógica de acesso a dados, promovendo separação de responsabilidades.
csharp
public interface IUserRepository
{
User GetById(int id);
}
public class UserRepository : IUserRepository
{
private readonly AppDbContext _context;
public UserRepository(AppDbContext context) => _context = context;
public User GetById(int id) => _context.Users.Find(id);
}
public class User { public int Id; public string Name; }
public class AppDbContext
{
public List<User> Users = new();
public User Find(int id) => Users.FirstOrDefault(u => u.Id == id);
}3. Unit of Work
Coordena múltiplos repositórios em uma única transação lógica.
csharp
public interface IUnitOfWork
{
IUserRepository Users { get; }
void Save();
}
public class UnitOfWork : IUnitOfWork
{
private readonly AppDbContext _context;
public IUserRepository Users { get; }
public UnitOfWork(AppDbContext context)
{
_context = context;
Users = new UserRepository(_context);
}
public void Save() => Console.WriteLine("Changes saved");
}4. Factory Method
Cria objetos sem expor a lógica de instanciação ao cliente.
csharp
public abstract class Animal
{
public abstract string Speak();
}
public class Dog : Animal
{
public override string Speak() => "Woof!";
}
public class AnimalFactory
{
public static Animal Create(string type) =>
type == "dog" ? new Dog() : throw new NotImplementedException();
}5. Dependency Injection
Promove o desacoplamento ao injetar dependências via construtor ou outro mecanismo.
csharp
public interface IMessageService
{
void Send(string message);
}
public class EmailService : IMessageService
{
public void Send(string message) => Console.WriteLine($"Email: {message}");
}
public class Notifier
{
private readonly IMessageService _service;
public Notifier(IMessageService service) => _service = service;
public void Notify(string msg) => _service.Send(msg);
}6. Adapter
Permite que duas interfaces incompatíveis trabalhem juntas.
csharp
public class LegacyPrinter
{
public void PrintText(string text) => Console.WriteLine(text);
}
public interface IPrinter
{
void Print(string content);
}
public class PrinterAdapter : IPrinter
{
private readonly LegacyPrinter _legacy;
public PrinterAdapter(LegacyPrinter legacy) => _legacy = legacy;
public void Print(string content) => _legacy.PrintText(content);
}7. Strategy
Permite trocar o algoritmo de forma dinâmica em tempo de execução.
csharp
public interface IDiscountStrategy
{
decimal ApplyDiscount(decimal amount);
}
public class ChristmasDiscount : IDiscountStrategy
{
public decimal ApplyDiscount(decimal amount) => amount * 0.9m;
}
public class Checkout
{
private readonly IDiscountStrategy _strategy;
public Checkout(IDiscountStrategy strategy) => _strategy = strategy;
public decimal CalculateTotal(decimal amount) => _strategy.ApplyDiscount(amount);
}8. Observer
Permite que um objeto notifique outros objetos quando seu estado muda.
csharp
public class TemperatureSensor
{
public event Action<float> TemperatureChanged;
public void UpdateTemperature(float temp)
{
TemperatureChanged?.Invoke(temp);
}
}
public class Display
{
public void Subscribe(TemperatureSensor sensor)
{
sensor.TemperatureChanged += t => Console.WriteLine($"Temp: {t}");
}
}9. Builder
Constrói objetos complexos passo a passo, com maior controle sobre o processo.
csharp
public class Pizza
{
public string Dough, Sauce, Topping;
}
public class PizzaBuilder
{
private readonly Pizza _pizza = new();
public PizzaBuilder AddDough(string dough) { _pizza.Dough = dough; return this; }
public PizzaBuilder AddSauce(string sauce) { _pizza.Sauce = sauce; return this; }
public PizzaBuilder AddTopping(string topping) { _pizza.Topping = topping; return this; }
public Pizza Build() => _pizza;
}10. Decorator
Adiciona funcionalidades a objetos de forma dinâmica, mantendo a mesma interface.
csharp
public interface IMessage
{
string GetContent();
}
public class SimpleMessage : IMessage
{
public string GetContent() => "Hello";
}
public class EncryptedMessage : IMessage
{
private readonly IMessage _inner;
public EncryptedMessage(IMessage inner) => _inner = inner;
public string GetContent() =>
Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(_inner.GetContent()));
}Como usar
Você pode compilar os arquivos individualmente ou integrar todos os exemplos em uma aplicação Console para testes.
Cada padrão está encapsulado em uma estrutura de classes para facilitar o entendimento e a reutilização em projetos reais.
Criado para fins educacionais e demonstração prática dos padrões mais usados em projetos com C# e .NET.