You are currently viewing SOLID Principles in Java: Quick Guide

SOLID Principles in Java: Quick Guide

Introduction

Writing clean, maintainable, and scalable code is a key skill for every Java developer. The SOLID principles are a set of five object-oriented design guidelines that help achieve that goal. These principles were introduced by Robert C. Martin (Uncle Bob) and have become a cornerstone of modern software design.

In this article, we’ll break down each of the SOLID principles with clear explanations and Java examples.


1. Single Responsibility Principle (SRP)

A class should have only one reason to change.

Each class should focus on one responsibility or job. This keeps your code modular and easier to test.

❌ Bad Example:

class Report {
    void generate() { /* logic */ }
    void saveToFile() { /* file I/O logic */ }
}

✅ Good Example:

class ReportGenerator {
    void generate() { /* logic */ }
}

class ReportSaver {
    void saveToFile() { /* file I/O logic */ }
}

2. Open/Closed Principle (OCP)

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

You should be able to add new features without modifying existing code, typically using interfaces or inheritance.

✅ Example:

interface Shape {
    double area();
}

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

class Square implements Shape {
    double side;
    public double area() { return side * side; }
}

You can add new shapes without touching existing logic.


3. Liskov Substitution Principle (LSP)

Subtypes must be substitutable for their base types.

You should be able to replace a parent class with a subclass without breaking the application.

✅ Example:

class Bird {
    void fly() {
        System.out.println("Flying");
    }
}

class Sparrow extends Bird { }

Bird bird = new Sparrow();
bird.fly(); // Works fine

⚠️ Violation would be introducing a subclass that can’t fly, breaking expectations.


4. Interface Segregation Principle (ISP)

No client should be forced to depend on methods it does not use.

Split large interfaces into smaller, role-specific ones.

❌ Bad Interface:

interface Machine {
    void print();
    void scan();
    void fax();
}

Not all classes need all methods.

✅ Better Approach:

interface Printer {
    void print();
}

interface Scanner {
    void scan();
}

5. Dependency Inversion Principle (DIP)

Depend on abstractions, not concretions.

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

❌ Tight Coupling:

class MySQLDatabase {
    void connect() { }
}

class App {
    MySQLDatabase db = new MySQLDatabase();
}

✅ With Abstraction:

interface Database {
    void connect();
}

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

class App {
    Database db;

    App(Database db) {
        this.db = db;
    }
}

Conclusion

The SOLID principles are not just theory — they help create Java code that is:

  • Easier to understand
  • Easier to maintain and test
  • More adaptable to change

Start applying them gradually, and you’ll notice your designs becoming more robust and flexible.

You can find the complete code of this article here in GitHub.

Noel Kamphoa

Experienced software engineer with expertise in Telecom, Payroll, and Banking. Now Senior Software Engineer at Societe Generale Paris.