SOLID Principles

Five principles of object-oriented design that make software more maintainable, flexible, and testable.


S — Single Responsibility Principle

A class should have one, and only one, reason to change.

Each class should do one thing. If a class handles both business logic and email sending, it has two reasons to change.

// Bad — two responsibilities
public class Order
{
    public void Calculate() { ... }
    public void SendConfirmationEmail() { ... }  // should not be here
}
 
// Good
public class Order { public void Calculate() { ... } }
public class OrderEmailService { public void SendConfirmation(Order o) { ... } }

O — Open/Closed Principle

Software entities should be open for extension, closed for modification.

Add new behaviour by adding new code (new class, new implementation), not by modifying existing code.

// Extend by adding new shapes, not by modifying AreaCalculator
public abstract class Shape { public abstract double Area(); }
public class Circle : Shape { ... }
public class Rectangle : Shape { ... }

L — Liskov Substitution Principle

Objects of a subtype should be substitutable for objects of the supertype without altering correctness.

If S extends T, you should be able to use S anywhere T is expected.

Classic violation: Square extends Rectangle but breaks when you set width/height independently.


I — Interface Segregation Principle

Clients should not be forced to depend on interfaces they do not use.

Prefer many small, focused interfaces over one large “fat” interface.

// Bad
interface IWorker { void Work(); void Eat(); void Sleep(); }
 
// Good
interface IWorkable { void Work(); }
interface IFeedable { void Eat(); }
interface ISleepable { void Sleep(); }

D — Dependency Inversion Principle

High-level modules should not depend on low-level modules. Both should depend on abstractions.

Program to interfaces, not implementations.

// Bad — high-level depends on low-level
public class OrderService { private SqlRepository _repo = new SqlRepository(); }
 
// Good — both depend on IOrderRepository abstraction
public class OrderService { private IOrderRepository _repo; }
public class SqlRepository : IOrderRepository { ... }
public class InMemoryRepository : IOrderRepository { ... }

DIP is implemented mechanically by Dependency-Injection.


See also