SOLID is a set of five object-oriented design principles that help developers write maintainable, scalable, and robust code in Java.

Why do you need SOLID?
SOLID is a set of object-oriented programming principles introduced by Robert Martin (Uncle Bob) in 1995. Their idea is to avoid dependencies between code components. If there are a large number of dependencies, such code is difficult to maintain.
Its main problems are:
- Rigidity: each change causes many other changes
- Fragility: changes in one part break the work of other parts
- Immobility: code cannot be reused outside of its context
1. S – Single Responsibility Principle (SRP)
A class should have only one reason to change.
Each class should focus on one responsibility only to improve maintainability.
✅ Example
// Violating SRP: Class handles both user data & database operations
class User {
void saveToDatabase() { /* Save user to DB */ }
}
// Applying SRP: Separate responsibilities
class User { /* User properties and methods */ }
class UserRepository {
void save(User user) { /* Save user to DB */ }
}
🔹 Why? The User class should not handle persistence logic.
2. O – Open/Closed Principle (OCP)
Software entities should be open for extension but closed for modification.
Instead of modifying existing code, extend it using polymorphism (inheritance or interfaces).
✅ Example
// Violating OCP: Modifying existing code for new shape types
class Shape {
String type;
}
class AreaCalculator {
double calculate(Shape shape) {
if (shape.type.equals("Circle")) { /* logic */ }
else if (shape.type.equals("Rectangle")) { /* logic */ }
return 0;
}
}
// Applying OCP: Extend functionality without modifying existing code
interface Shape {
double calculateArea();
}
class Circle implements Shape {
double radius;
public double calculateArea() { return Math.PI * radius * radius; }
}
class Rectangle implements Shape {
double length, width;
public double calculateArea() { return length * width; }
}
🔹 Why? Adding a new shape (e.g., Triangle) doesn’t modify existing code.
3. L – Liskov Substitution Principle (LSP)
The Liskov Substitution Principle requires that subclasses must be substitutable for their base classes without breaking the behavior. Here, substituting Bird with Ostrich violates this, because Ostrich cannot fly and throws an exception.
✅ Example
// Violating LSP: A subclass changes expected behavior
class Bird {
void fly() { System.out.println("Flying"); }
}
class Penguin extends Bird {
void fly() { throw new UnsupportedOperationException("Penguins can't fly"); }
}
🔹 Issue? A Penguin is a Bird but cannot fly, violating expectations.
✅ Applying LSP
interface Bird { }
interface FlyingBird extends Bird {
void fly();
}
class Sparrow implements FlyingBird {
public void fly() { System.out.println("Flying"); }
}
class Penguin implements Bird { /* No fly method */ }
🔹 Why? Penguin now correctly follows expectations without modifying behavior.
4. I – Interface Segregation Principle (ISP)
Clients should not be forced to implement unnecessary methods.
Large interfaces should be broken into smaller, more specific interfaces.
✅ Example
// Violating ISP: A class is forced to implement unrelated methods
interface Worker {
void work();
void eat();
}
class Robot implements Worker {
public void work() { /* Works */ }
public void eat() { throw new UnsupportedOperationException("Robots don't eat"); }
}
// Applying ISP: Split into multiple interfaces
interface Workable {
void work();
}
interface Eatable {
void eat();
}
class Human implements Workable, Eatable {
public void work() { /* Works */ }
public void eat() { /* Eats */ }
}
class Robot implements Workable {
public void work() { /* Works */ }
}
🔹 Why? Now, Robot isn’t forced to implement eat().
5. D – Dependency Inversion Principle (DIP)
High-level modules should not depend on low-level modules. Both should depend on abstractions.
Bad Example (Violating DIP)
Here, Application directly depends on MySQLDatabase.
class MySQLDatabase {
void connect() { System.out.println("Connecting to MySQL"); }
}
class Application {
private MySQLDatabase db = new MySQLDatabase();
void start() { db.connect(); }
}Why is this bad?
- If we switch databases, we must modify
Application.
Correct Example (Applying DIP)
Instead of hardcoding dependencies, we use an interface:
interface Database {
void connect();
}
class MySQLDatabase implements Database {
public void connect() { System.out.println("Connecting to MySQL"); }
}
class Application {
private Database db;
public Application(Database db) { this.db = db; }
void start() { db.connect(); }
}Now, we can switch to PostgreSQL without modifying Application.
Conclusion
SOLID principles make Java code:
✔ More maintainable
✔ More scalable
✔ Less coupled
✔ Easier to test
Read other awesome articles in Medium.com or in akcoding’s posts.
OR
Join us on YouTube Channel
OR Scan the QR Code to Directly open the Channel 👉

