SOLID Principles
Master SOLID design principles for maintainable, scalable code.
A Simple Analogy
SOLID principles are like architectural guidelines for buildings. Good architects follow proven patterns—strong foundations, single purpose for each room, flexibility to renovate. Code needs the same principles to avoid becoming a brittle mess.
What Are SOLID Principles?
SOLID is an acronym for five design principles that make software more understandable, flexible, and maintainable. They guide proper class design and responsibility distribution.
S - Single Responsibility Principle
A class should have one reason to change (one responsibility).
// Bad: User class doing too much
public class User
{
public string Name { get; set; }
public void SaveToDatabase() { }
public void SendEmail() { }
public void ValidateInput() { }
}
// Good: Separated concerns
public class User
{
public string Name { get; set; }
}
public class UserRepository
{
public void Save(User user) { }
}
public class EmailService
{
public void SendWelcomeEmail(User user) { }
}
public class UserValidator
{
public bool Validate(User user) { }
}
O - Open/Closed Principle
Classes should be open for extension, closed for modification.
// Bad: Modify class for each payment type
public class PaymentProcessor
{
public void Process(string type, decimal amount)
{
if (type == "CreditCard") { /* ... */ }
else if (type == "PayPal") { /* ... */ }
}
}
// Good: Extend with new implementations
public interface IPaymentMethod
{
void Process(decimal amount);
}
public class CreditCardPayment : IPaymentMethod
{
public void Process(decimal amount) { }
}
public class PayPalPayment : IPaymentMethod
{
public void Process(decimal amount) { }
}
public class PaymentProcessor
{
public void Process(IPaymentMethod method, decimal amount)
{
method.Process(amount); // Works with any implementation
}
}
L - Liskov Substitution Principle
Derived classes must be substitutable for base classes.
// Bad: Square isn't a true Rectangle
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: Correct hierarchy
public interface IShape
{
int Area { get; }
}
public class Rectangle : IShape
{
public int Width { get; set; }
public int Height { get; set; }
public int Area => Width * Height;
}
public class Square : IShape
{
public int Side { get; set; }
public int Area => Side * Side;
}
I - Interface Segregation Principle
Clients shouldn't depend on interfaces they don't use.
// Bad: Fat interface
public interface IWorker
{
void Work();
void Eat();
void Sleep();
}
public class Robot : IWorker
{
public void Work() { }
public void Eat() { } // Doesn't make sense
public void Sleep() { } // Doesn't make sense
}
// Good: Segregated interfaces
public interface IWorker
{
void Work();
}
public interface ILivingBeing
{
void Eat();
void Sleep();
}
public class Robot : IWorker
{
public void Work() { }
}
public class Human : IWorker, ILivingBeing
{
public void Work() { }
public void Eat() { }
public void Sleep() { }
}
D - Dependency Inversion Principle
Depend on abstractions, not concretions.
// Bad: High-level depends on low-level
public class OrderService
{
private EmailNotifier _emailer = new();
public void CreateOrder(Order order)
{
_emailer.Send("Order created");
}
}
// Good: Both depend on abstraction
public interface INotifier
{
void Send(string message);
}
public class OrderService
{
private readonly INotifier _notifier;
public OrderService(INotifier notifier)
{
_notifier = notifier;
}
public void CreateOrder(Order order)
{
_notifier.Send("Order created");
}
}
Real-World Benefits
- Easier testing: Inject mocks
- Flexible maintenance: Change implementations easily
- Clear responsibilities: Understand code purpose
- Reusability: Use components in new ways
- Scalability: Add features without breaking existing code
Related Concepts to Explore
- Design patterns (many use SOLID)
- Clean Code principles
- Test-driven development
- Refactoring techniques
Summary
SOLID principles guide proper object-oriented design. Apply them to write code that's flexible, testable, and maintainable as projects grow.