Section 1 of 5

SOLID Principles

🎯 What You'll Learn

  • Single Responsibility Principle
  • Open/Closed Principle
  • Liskov Substitution Principle
  • Interface Segregation Principle
  • Dependency Inversion Principle

What is SOLID?

SOLID is a set of five design principles that make software more maintainable, flexible, and scalable.

S - Single Responsibility Principle (SRP)

A class should have only one reason to change.

❌ Bad: Multiple Responsibilities C#
public class OrderProcessor
{
    public void ProcessOrder(Order order)
    {
        // Validate order
        // Save to database
        // Send email
        // Generate invoice
    }
}
✅ Good: Single Responsibility C#
public class OrderValidator
{
    public bool Validate(Order order) { }
}

public class OrderRepository
{
    public void Save(Order order) { }
}

public class EmailService
{
    public void SendOrderConfirmation(Order order) { }
}

public class InvoiceGenerator
{
    public void Generate(Order order) { }
}

O - Open/Closed Principle (OCP)

Open for extension, closed for modification.

❌ Bad: Modifying Existing Code C#
public class DiscountCalculator
{
    public decimal Calculate(decimal price, string customerType)
    {
        if (customerType == "Regular")
            return price * 0.95m;
        else if (customerType == "Premium")
            return price * 0.90m;
        return price;
    }
}
✅ Good: Extension via Abstraction C#
public interface IDiscountStrategy
{
    decimal Calculate(decimal price);
}

public class RegularDiscount : IDiscountStrategy
{
    public decimal Calculate(decimal price) => price * 0.95m;
}

public class PremiumDiscount : IDiscountStrategy
{
    public decimal Calculate(decimal price) => price * 0.90m;
}

L - Liskov Substitution Principle (LSP)

Subtypes must be substitutable for their base types.

❌ Bad: Violates LSP C#
public class Rectangle
{
    public virtual int Width { get; set; }
    public virtual int Height { get; set; }
}

public class Square : Rectangle
{
    public override int Width
    {
        set { base.Width = base.Height = value; }
    }
}
✅ Good: Separate Abstractions C#
public interface IShape
{
    int GetArea();
}

public class Rectangle : IShape
{
    public int Width { get; set; }
    public int Height { get; set; }
    public int GetArea() => Width * Height;
}

public class Square : IShape
{
    public int Side { get; set; }
    public int GetArea() => Side * Side;
}

I - Interface Segregation Principle (ISP)

Clients should not depend on interfaces they don't use.

❌ Bad: Fat Interface C#
public interface IProduct
{
    void Add();
    void Update();
    void Delete();
    void Print();
    void Export();
}
✅ Good: Segregated Interfaces C#
public interface IProductRepository
{
    void Add(Product product);
    void Update(Product product);
    void Delete(int id);
}

public interface IPrintable
{
    void Print();
}

public interface IExportable
{
    void Export();
}

D - Dependency Inversion Principle (DIP)

Depend on abstractions, not concretions.

❌ Bad: Depends on Concrete Class C#
public class OrderService
{
    private readonly SqlServerRepository _repository;
    
    public OrderService()
    {
        _repository = new SqlServerRepository();
    }
}
✅ Good: Depends on Abstraction C#
public class OrderService
{
    private readonly IOrderRepository _repository;
    
    public OrderService(IOrderRepository repository)
    {
        _repository = repository;
    }
}

Key Takeaways

  • SRP: One class, one responsibility
  • OCP: Extend behavior without modifying code
  • LSP: Subtypes must be substitutable
  • ISP: Small, focused interfaces
  • DIP: Depend on abstractions, not implementations