Skip to content

SOLID Principles para .NET Senior

📋 Introdução

SOLID é um acrônimo para os cinco princípios fundamentais do design de software orientado a objetos, criados por Robert C. Martin.

🎯 Os 5 Princípios

1. S - Single Responsibility Principle (SRP)

Definição: Uma classe deve ter apenas uma razão para mudar.

❌ Violação do SRP

csharp
public class UserService
{
    public void CreateUser(User user)
    {
        ValidateUser(user);
        SaveUser(user);
        SendWelcomeEmail(user);
        LogUserCreation(user);
    }
    
    private void ValidateUser(User user) { }
    private void SaveUser(User user) { }
    private void SendWelcomeEmail(User user) { }
    private void LogUserCreation(User user) { }
}

✅ Aplicando SRP

csharp
public class UserService
{
    private readonly IUserRepository _userRepository;
    private readonly IEmailService _emailService;
    private readonly ILogger _logger;
    
    public UserService(IUserRepository userRepository, 
                      IEmailService emailService, 
                      ILogger logger)
    {
        _userRepository = userRepository;
        _emailService = emailService;
        _logger = logger;
    }
    
    public void CreateUser(User user)
    {
        _userRepository.Save(user);
        _emailService.SendWelcomeEmail(user);
        _logger.LogUserCreation(user);
    }
}

2. O - Open/Closed Principle (OCP)

Definição: Entidades devem estar abertas para extensão, mas fechadas para modificação.

❌ Violação do OCP

csharp
public class DiscountCalculator
{
    public decimal CalculateDiscount(Order order)
    {
        if (order.CustomerType == CustomerType.Regular)
            return order.Total * 0.1m;
        else if (order.CustomerType == CustomerType.Premium)
            return order.Total * 0.2m;
        else if (order.CustomerType == CustomerType.VIP)
            return order.Total * 0.3m;
        
        return 0;
    }
}

✅ Aplicando OCP

csharp
public abstract class DiscountStrategy
{
    public abstract decimal CalculateDiscount(Order order);
}

public class RegularCustomerDiscount : DiscountStrategy
{
    public override decimal CalculateDiscount(Order order) => order.Total * 0.1m;
}

public class PremiumCustomerDiscount : DiscountStrategy
{
    public override decimal CalculateDiscount(Order order) => order.Total * 0.2m;
}

public class DiscountCalculator
{
    private readonly Dictionary<CustomerType, DiscountStrategy> _strategies;
    
    public DiscountCalculator()
    {
        _strategies = new Dictionary<CustomerType, DiscountStrategy>
        {
            { CustomerType.Regular, new RegularCustomerDiscount() },
            { CustomerType.Premium, new PremiumCustomerDiscount() }
        };
    }
    
    public decimal CalculateDiscount(Order order)
    {
        if (_strategies.TryGetValue(order.CustomerType, out var strategy))
            return strategy.CalculateDiscount(order);
        
        return 0;
    }
}

3. L - Liskov Substitution Principle (LSP)

Definição: Objetos de uma superclasse devem poder ser substituídos por objetos de suas subclasses sem quebrar a aplicação.

❌ Violação do LSP

csharp
public class Rectangle
{
    public virtual int Width { get; set; }
    public virtual int Height { get; set; }
    
    public virtual int Area => Width * Height;
}

public class Square : Rectangle
{
    public override int Width
    {
        get => base.Width;
        set
        {
            base.Width = value;
            base.Height = value;
        }
    }
    
    public override int Height
    {
        get => base.Height;
        set
        {
            base.Width = value;
            base.Height = value;
        }
    }
}

✅ Aplicando LSP

csharp
public abstract class Shape
{
    public abstract int Area { get; }
}

public class Rectangle : Shape
{
    public int Width { get; set; }
    public int Height { get; set; }
    
    public override int Area => Width * Height;
}

public class Square : Shape
{
    public int Side { get; set; }
    
    public override int Area => Side * Side;
}

4. I - Interface Segregation Principle (ISP)

Definição: Muitas interfaces específicas são melhores que uma interface geral.

❌ Violação do ISP

csharp
public interface IWorker
{
    void Work();
    void Eat();
    void Sleep();
}

public class Human : IWorker
{
    public void Work() { }
    public void Eat() { }
    public void Sleep() { }
}

public class Robot : IWorker
{
    public void Work() { }
    public void Eat() { throw new NotImplementedException(); }
    public void Sleep() { throw new NotImplementedException(); }
}

✅ Aplicando ISP

csharp
public interface IWorkable
{
    void Work();
}

public interface IEatable
{
    void Eat();
}

public interface ISleepable
{
    void Sleep();
}

public class Human : IWorkable, IEatable, ISleepable
{
    public void Work() { }
    public void Eat() { }
    public void Sleep() { }
}

public class Robot : IWorkable
{
    public void Work() { }
}

5. D - Dependency Inversion Principle (DIP)

Definição: Dependa de abstrações, não de implementações concretas.

❌ Violação do DIP

csharp
public class EmailNotifier
{
    public void SendNotification(string message) { }
}

public class OrderService
{
    private readonly EmailNotifier _emailNotifier;
    
    public OrderService()
    {
        _emailNotifier = new EmailNotifier();
    }
    
    public void ProcessOrder(Order order)
    {
        _emailNotifier.SendNotification("Order processed");
    }
}

✅ Aplicando DIP

csharp
public interface INotifier
{
    void SendNotification(string message);
}

public class EmailNotifier : INotifier
{
    public void SendNotification(string message) { }
}

public class SmsNotifier : INotifier
{
    public void SendNotification(string message) { }
}

public class OrderService
{
    private readonly INotifier _notifier;
    
    public OrderService(INotifier notifier)
    {
        _notifier = notifier;
    }
    
    public void ProcessOrder(Order order)
    {
        _notifier.SendNotification("Order processed");
    }
}

🏗️ Aplicação Prática em .NET

Dependency Injection Container

csharp
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped<IUserRepository, UserRepository>();
        services.AddScoped<IEmailService, EmailService>();
        services.AddScoped<ILogger, Logger>();
        services.AddScoped<IUserService, UserService>();
    }
}

Repository Pattern com SOLID

csharp
public interface IRepository<T> where T : class
{
    Task<T> GetByIdAsync(int id);
    Task<IEnumerable<T>> GetAllAsync();
    Task AddAsync(T entity);
    Task UpdateAsync(T entity);
    Task DeleteAsync(int id);
}

public interface IUserRepository : IRepository<User>
{
    Task<User> GetByEmailAsync(string email);
}

public class UserRepository : IUserRepository
{
    private readonly DbContext _context;
    
    public UserRepository(DbContext context) => _context = context;
    
    public async Task<User> GetByIdAsync(int id)
    {
        return await _context.Users.FindAsync(id);
    }
    
    public async Task<User> GetByEmailAsync(string email)
    {
        return await _context.Users.FirstOrDefaultAsync(u => u.Email == email);
    }
}

📚 Benefícios dos Princípios SOLID

1. Manutenibilidade

  • Código mais fácil de entender e modificar
  • Mudanças isoladas em componentes específicos

2. Testabilidade

  • Classes menores e mais focadas
  • Dependências injetadas facilitam mocking

3. Extensibilidade

  • Novas funcionalidades sem modificar código existente
  • Polimorfismo e herança bem utilizados

4. Reutilização

  • Componentes modulares e independentes
  • Interfaces bem definidas

⚠️ Pontos de Atenção

  • Não force abstrações: Use apenas quando necessário
  • Mantenha simplicidade: Over-engineering pode complicar
  • Considere o contexto: Nem sempre todos os princípios se aplicam
  • Performance: Abstrações podem impactar performance
  • Complexidade: Muitas interfaces podem aumentar complexidade

📖 Recursos Adicionais

Livros Recomendados

  • "Clean Code" - Robert C. Martin
  • "Agile Principles, Patterns, and Practices" - Robert C. Martin
  • "Refactoring" - Martin Fowler

Artigos e Blogs

  • Martin Fowler's Blog
  • Uncle Bob's Blog
  • Microsoft .NET Documentation