π SOLID Principles: Quick Reference Guide
The SOLID principles are five design principles intended to make software designs more understandable, flexible, and maintainable. They are the backbone of good Object-Oriented Design (OOD).
S: Single Responsibility Principle (SRP)
π― The Rule: A class or module should have only one reason to change. It should have only one job.
π‘ Why: Reduces coupling, improves testability, and makes debugging easier.
π οΈ How to Apply: If a class is doing too many unrelated things (e.g., handling business logic AND logging AND database persistence), split it into multiple, focused classes.
β Bad Example:
class Employee {
public void calculatePay() { /* Business Logic */ }
public void saveToDatabase() { /* DB Logic */ } // Responsibility 2
public void logActivity() { /* Logging Logic */ } // Responsibility 3
}
O: Open/Closed Principle (OCP)
π― The Rule: Software entities (classes, modules, functions) should be open for extension, but closed for modification.
π‘ Why: Allows you to add new features without changing existing, working code (minimizing the risk of regressions).
π οΈ How to Apply: Use abstraction (interfaces or abstract classes) and polymorphism. If you need new behavior, create a new implementation of the interface instead of changing the core class body.
β Bad Example:
A class that uses a massive switch statement or long if/else if chain to handle various types of objects.
L: Liskov Substitution Principle (LSP)
π― The Rule: Subtypes must be substitutable for their base types without breaking the application.
π‘ Why: Ensures that when you use a parent class reference, the child class behaves exactly as expected (maintaining behavioral contracts).
π οΈ How to Apply: When creating subclasses, ensure they honor the contract established by the parent class. If a subclass fails to meet a fundamental promise of the base class, it violates LSP.
β Bad Example:
A subclass that throws an unexpected exception or returns null when the base class promised a non-null result.
I: Interface Segregation Principle (ISP)
π― The Rule: Clients should not be forced to depend on methods they do not use. Keep interfaces small and focused.
π‘ Why: Prevents clients from being coupled to functionality they don't need, making the code cleaner and reducing unnecessary dependencies.
π οΈ How to Apply: Instead of one huge MegaService interface, create several smaller, role-specific interfaces (e.g., Runnable, Serializable).
β Bad Example:
A single interface that groups methods for completely different purposes (e.g., DataService which includes both read() and write()).
D: Dependency Inversion Principle (DIP)
π― The Rule: High-level modules should not depend on low-level modules. Both should depend on abstractions (interfaces), not concretions.
π‘ Why: This is the key to decoupling. It allows you to swap out real implementations for mock or fake ones (essential for unit testing and modularity).
π οΈ How to Apply: If Class A needs functionality from Class B, make Class A depend on an IB (interface) that defines the required functionality, not directly on a concrete Class B.
β Bad Example (Tight Coupling):
class OrderProcessor {
private DatabaseAdapter db = new MySQLAdapter(); // Depends on a concrete implementation!
public void process() {
db.save();
}
}
π Summary Takeaway for Engineers
| Principle | Goal | Core Benefit | What it Solves |
|---|---|---|---|
| SRP | Separation of Concerns | Maintainability & Clarity | Bloated classes |
| OCP | Flexibility | Extensibility | Brittle code that needs frequent updates |
| LSP | Behavioral Consistency | Robustness | Broken inheritance/polymorphism |
| ISP | Focus | Low Coupling | Clients depending on unnecessary methods |
| DIP | Decoupling | Testability & Swapability | Tight coupling between layers/services |
β The Ultimate Goal
SOLID principles aim for software that is:
- Robust: Less likely to break when requirements change.
- Testable: Easy to isolate and test individual components.
- Flexible: Easy to add new features or swap dependencies.