SOLID in Java

S – Single Responsibility Principle (SRP)

A class should have only one reason to change, meaning it should only have one responsibility.

// Bad Example: Single class has multiple responsibilities
class User {
    void saveUserToDatabase() { /* code to save user */ }
    void sendEmail() { /* code to send email */ }
}

// Good Example: Separate responsibilities
class User {
    private String name;
    private String email;
    // getters and setters
}

class UserRepository {
    void save(User user) { /* code to save user */ }
}

class EmailService {
    void sendEmail(User user) { /* code to send email */ }
}

O – Open/Closed Principle (OCP)

Software entities (classes, modules, functions) should be open for extension but closed for modification.

// Bad: Modifying class when adding new behavior
class Rectangle {
    double length, width;
}

class AreaCalculator {
    double calculateRectangleArea(Rectangle r) { return r.length * r.width; }
}

// Good: Open for extension
interface Shape {
    double area();
}

class Rectangle implements Shape {
    double length, width;
    public double area() { return length * width; }
}

class Circle implements Shape {
    double radius;
    public double area() { return Math.PI * radius * radius; }
}

class AreaCalculator {
    double calculateArea(Shape shape) { return shape.area(); }
}

L – Liskov Substitution Principle (LSP)

Objects of a superclass should be replaceable with objects of a subclass without affecting correctness.

// Bad: Subclass breaks parent contract
class Bird {
    void fly() {}
}

class Ostrich extends Bird {
    @Override
    void fly() { throw new UnsupportedOperationException(); }
}

// Good: Separate flying behavior
interface Flyable {
    void fly();
}

class Sparrow extends Bird implements Flyable {
    public void fly() {}
}

class Ostrich extends Bird { } // does not implement Flyable

I – Interface Segregation Principle (ISP)

Clients should not be forced to depend on interfaces they do not use. Split fat interfaces into smaller, more specific ones.

// Bad: Fat interface
interface Worker {
    void work();
    void eat();
}

class Robot implements Worker {
    public void work() { /* working */ }
    public void eat() { throw new UnsupportedOperationException(); }
}

// Good: Segregated interfaces
interface Workable { void work(); }
interface Eatable { void eat(); }

class Human implements Workable, Eatable {
    public void work() { }
    public void eat() { }
}

class Robot implements Workable {
    public void work() { }
}

D – Dependency Inversion Principle (DIP)

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

// Bad: High-level module depends on low-level module
class MySQLDatabase {
    void connect() { }
}

class UserService {
    private MySQLDatabase db = new MySQLDatabase();
    void saveUser() { db.connect(); }
}

// Good: Depend on abstraction
interface Database {
    void connect();
}

class MySQLDatabase implements Database {
    public void connect() { }
}

class UserService {
    private Database db;
    UserService(Database db) { this.db = db; }
    void saveUser() { db.connect(); }
}

Summary of SOLID:

  • SRP → One class, one responsibility
  • OCP → Extend, don’t modify
  • LSP → Subtypes replace supertypes
  • ISP → Many small interfaces, not one fat interface
  • DIP → Depend on abstractions, not concrete classes

Leave a Reply