S.O.L.I.D Principles
- π§ What is SOLID?
- π§± 1. Single Responsibility Principle (SRP)
- π§± 2. Open/Closed Principle (OCP)
- π§± 3. Liskov Substitution Principle (LSP)
- π§± 4. Interface Segregation Principle (ISP)
- π§± 5. Dependency Inversion Principle (DIP)
- π§Ύ SOLID Principles : Summary Table
π§ What is SOLID?
S.O.L.I.D is an acronym for:
- S: Single Responsibility Principle
- O: Open/Closed Principle
- L: Liskov Substitution Principle
- I: Interface Segregation Principle
- D: Dependency Inversion Principle
These principles were introduced by Robert C. Martin (Uncle Bob) and are foundational to good software design.
π Letβs go one-by-one with simple intuition, analogy, and examples.
π§± 1. Single Responsibility Principle (SRP)
A class should have only one reason to change.
π― Real-world analogy:
- A chef cooks food
- A waiter serves customers Donβt mix responsibilities.
π» Example β β Violation:
class Report {
String text;
void print() {
// print logic
}
void saveToFile() {
// file I/O logic
}
}
This class does two things: manage report data and handle I/O.
β Refactored:
class Report {
String text;
// Only holds data and formatting
}
class ReportPrinter {
void print(Report r) { /* ... */ }
}
class ReportSaver {
void saveToFile(Report r) { /* ... */ }
}
π§± 2. Open/Closed Principle (OCP)
Software entities should be open for extension, but closed for modification.
π― Real-world analogy:
We can plug in new USB devices without rewriting our motherboard.
π» Example β β Violation:
class PaymentProcessor {
void pay(String type) {
if (type.equals("credit")) { /* ... */ }
else if (type.equals("upi")) { /* ... */ }
}
}
- Adding new payment methods β modify existing class = β
β Refactored: Using Polymorphism
interface PaymentMethod {
void pay();
}
class CreditCardPayment implements PaymentMethod {
public void pay() { /* ... */ }
}
class UpiPayment implements PaymentMethod {
public void pay() { /* ... */ }
}
class PaymentProcessor {
void pay(PaymentMethod method) {
method.pay(); // open for extension, closed for modification
}
}
π§± 3. Liskov Substitution Principle (LSP)
Subtypes must be substitutable for their base types without breaking behavior.
π― Real-world analogy:
If every electric car is a kind of car, it should still drive, stop, turn like any car.
π» Example β β Violation:
class Bird {
void fly() { }
}
class Ostrich extends Bird {
void fly() { throw new UnsupportedOperationException(); }
}
Ostrich canβt fly, so substituting it breaks the logic.
β Refactored:
Donβt force all birds to fly β separate the concept.
interface Bird { void eat(); }
interface FlyingBird extends Bird {
void fly();
}
π§± 4. Interface Segregation Principle (ISP)
Clients should not be forced to depend on interfaces they donβt use.
π― Real-world analogy:
Donβt give a printer the controls of a 3D scanner if it doesnβt need it.
π» Example β β Violation:
interface Machine {
void print();
void scan();
void fax();
}
class SimplePrinter implements Machine {
public void print() { }
public void scan() { /* not supported */ }
public void fax() { /* not supported */ }
}
β Refactored:
interface Printer { void print(); }
interface Scanner { void scan(); }
class SimplePrinter implements Printer { ... }
Split big interfaces into role-specific ones.
π§± 5. Dependency Inversion Principle (DIP)
High-level modules should not depend on low-level modules β both should depend on abstractions.
π― Real-world analogy:
We donβt directly plug the toaster into the power plant β rather go through a standard plug interface.
π» Example β β Violation:
class MySQLDatabase {
void connect() { }
}
class UserService {
MySQLDatabase db = new MySQLDatabase(); // tight coupling β
}
β Refactored: Using Interface
interface Database {
void connect();
}
class MySQLDatabase implements Database {
public void connect() { }
}
class UserService {
Database db;
UserService(Database db) {
this.db = db;
}
}
Now we can inject any DB (PostgreSQL
, MockDB
, etc.)
π§Ύ SOLID Principles : Summary Table
Principle | What it Means | Helps Us With |
---|---|---|
SRP | One job per class | Maintainability |
OCP | Extend without modifying | Flexibility |
LSP | Subclass should behave like parent | Reliability |
ISP | Small, focused interfaces | Simplicity |
DIP | Depend on interfaces, not concrete | Testability, decoupling |