Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion
In the Java programming language, these five important principles: Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion, are known as the SOLID principles. They help Java developers create custom user-defined program source code that is easy for every Java software developer to maintain, enhance, easily test and debug, and reuse multiple times using modular programming concepts.

S — Single Responsibility Principle (SRP) concept in Java.
The important single responsibility concept in Java programs requires that there should be only one significant reason for making any kind of custom manual modification to a user-defined class.
In general, a user-defined class should have only a few responsibilities.
Example of S — Bad the Single Responsibility Principle.
class Employee {
void calculateSalary() {
// This class is used to calculate employee salary
}
void saveToDatabase() {
// This class is used to save employee salary details
}
void generateReport() {
// This class is used to generate or display employee salary reports
}
}
Here are the three main roles of S — Single Responsibility Principle (SRP).
- Calculating employee salaries.
- Storing employee salaries in the database.
- Generating employee salary details reports.
Example of Improved S — the Single Responsibility Principle.
class SalaryCalculator {
void calculateSalary() {
//Here we set code for count emloyee salary
}
}
class EmployeeRepository {
void save(){
// Here we set code for save employee salary database information
}
}
class ReportGenerator {
void generate() {
// Here we set code for display or generate employee salary report
}
}
Complete Example of S — Single Responsibility Principle.
class EmpSalaryManagement {
// Here we set Responsibility 1: count employee salary
void calculateSalary(double empSalary) {
double hra = empSalary * 0.31;
double da = empSalary * 0.17;
double ta = empSalary * 0.23;
double completeSalary = empSalary + hra + da + ta;
System.out.println(“Total Salary of Employee Is -: ” + completeSalary);
}
}
class EmployeeDataRecord {
// Here we set Responsibility 2: Save employee salary data or details
void save(String emp_name, int id) {
System.out.println(“-:- Employee Record save to database -:-“);
System.out.println(“Employee ID -: ” + id);
System.out.println(“Employee Name -: ” + emp_name);
}
}
class EmpReportCreator {
// Here we set Responsibility 3: Create employee total salary report
void generate(String emp_name, int emp_id, double totalsalary) {
System.out.println(“\n—– Employee Salary Details —–“);
System.out.println(“Employee ID Is -: ” + emp_id);
System.out.println(“Employee Name Is -: ” + emp_name);
System.out.println(“Basic Salary Is -: ” + totalsalary);
System.out.println(“———##################——————“);
}
}
//Here we set Main class
public class Main {
public static void main(String[] args) {
String emp_name = “Siddhi Deora”;
int emp_id = 1109;
double empSalary = 90000;
// Here we create employee class objects
EmpSalaryManagement salmanagement = new EmpSalaryManagement();
EmployeeDataRecord emprecord = new EmployeeDataRecord();
EmpReportCreator empreport = new EmpReportCreator();
// Here we manage or calculate employee salary
salmanagement.calculateSalary(empSalary);
// Here we save employee details
emprecord.save(emp_name, emp_id);
// Here we generate employee salary report
empreport.generate(emp_name, emp_id, empSalary);
}
}
The main idea of the S — Single Responsibility Principle in Java.
- A user-defined custom Java class → and a class’s responsibilities
O — Open/Closed Principle (OCP) concept in Java.
In a Java program, the Open/Closed Concept requires methods in a user-defined class to be open to extension by software entities. But for the average Java user, it should be closed to any custom modifications and updates.
This should allow Java developers to manually add new, important custom class functionality without modifying existing, programmatically tested source code.
Example of the Bad O — Open/Closed Principle (OCP).
class Payment {
void pay(String type) {
if (type.equals(“UPI Method”)) {
// Here we can create code for the UPI payment method
}
else if (type.equals(“Credit CARD”)) {
// Here we can create code for the Credit Card payment method
}
}
}
Here, in this incorrect open/closed concept source code method, every time we add a new payment method, the Java developer has to modify Payment first.
Example of the Better O — Open/Closed Principle (OCP).
interface Payment {
void pay();
}
class UpiPayment implements Payment {
public void pay() {
System.out.println(“We use UPI Payment Method”);
}
}
class CardPayment implements Payment {
public void pay() {
System.out.println(“We use Card Payment Method”);
}
}
Then, the Java developer can add to it.
class CashPayment implements Payment {
public void pay() {
System.out.println(“We use Cash Payment Method”);
}
}
Complete Example of O — Open/Closed Principle (OCP) Principle.
interface PaymentGateway {
void paymentMethod();
}
// Payment Gateway Method 1: set UPI Payment
class UpiPayment implements PaymentGateway {
public void paymethod() {
System.out.println(“———-List of Available Payment Gateway Method——————“);
System.out.println(“You Can Use UPI Payment Gateway Method”);
}
}
// Payment Gateway Method 2: set Card Payment
class CardPayment implements PaymentGateway {
public void paymethod() {
System.out.println(“You Can Use Debit/Credit Card Payment Gateway Method”);
}
}
// Payment Gateway Method 3: set Cash Payment
class CashPayment implements PaymentGateway {
public void paymethod() {
System.out.println(“You Can Use Cash Payment Method”);
}
}
// Payment Gateway Method 4: set Online Payment
class OnlineMethod implements PaymentGateway {
public void paymethod() {
System.out.println(“You Can Use Online Payment Method”);
System.out.println(“————————————————————–#####################——————————–“);
}
}
// Here we define a Main payment gateway class
public class Main {
public static void main(String[] args) {
//here we create paymentgateway class objects
PaymentGateway upi = new UpiPayment();
PaymentGateway card = new CardPayment();
PaymentGateway cash = new CashPayment();
PaymentGateway online = new OnlineMethod();
// Here we execute all user-defined Payment Gateway methods interface
upi.paymethod();
card.paymethod();
cash.paymethod();
online.paymethod();
}
}
The Open/Closed Java Principle allows you to make changes to other classes without modifying existing Java classes.
The main idea of the O — Open/Closed Principle (OCP) Principle in Java.
- The Open/Closed Java Principle helps developers enhance the functionality of existing programs without modifying the existing program source code.
L — Liskov Substitution Principle (LSP) concept in Java.
Liskov Substitution Concept in Java Programs Methods Child class objects in a user-defined class should be modifiable from any user-defined class objects in the parent root or base class without manually breaking the program.
In general, if the Employee class is defined as a subclass of the Company class, then Java users should be able to use the Employee class wherever it is possible in the Company class.
Example of a bad Liskov Substitution Concept.
class Bird {
void canfly() {
System.out.println(“Bird Can Flying”);
}
}
class Sparrow extends Bird {
// Source code for Can Birds Fly
}
class Penguin extends Bird {
void canfly() {
throw new UnsupportedOperationException();
Here we create a Bird class called Penguin with exception behavior.
}
}
Remember, here Penguin is a bird in the Bird parent class, but due to its greater weight, it cannot perform the fly() class behavior expected from the Bird parent class.
Example of a Better Liskov Substitution Concept.
Separate capabilities.
class Bird {
void eat() {
System.out.println(“What Bird Eating”);
}
}
interface FlyingBird {
void fly();
}
class Sparrow extends Bird implements FlyingBird {
public void fly() {
System.out.println(“Can Bird Flying”);
}
}
class Penguin extends Bird {
// Unable to fly() required
}
Complete Example of Liskov Substitution Principal Concept.
class Bird {
// Here we set a common class behaviour of all birds subclass
void eating() {
System.out.println(“This Bird is Eating Food”);
}
}
// Here we set an Interface for birds class that can flying
interface FlyingBird {
void flying();
}
// Here we set a Parrot inherits Bird and implements FlyingBird
class Parrot extends Bird implements FlyingBird {
public void flying() {
System.out.println(“Parrot Can Flying”);
}
}
// Here we set a Pigeon inherits Bird and implements FlyingBird
class Pigeon extends Bird implements FlyingBird {
public void flying() {
System.out.println(“Pigeon Is Also Can Flying”);
}
}
// Here Penguin inherits Bird category but due to overweight it does not implement FlyingBird capabilities
class Penguin extends Bird {
// Penguin is bird but it cannot fly.
}
// here we define a Main class
public class Main {
public static void main(String[] args) {
// here we create a Parrot subclass object
Parrot parrot = new Parrot();
System.out.println(“—– Parrot Bird Details —–“);
parrot.eating();
parrot.flying();
// here we create a Pigeon subclass object
Pigeon pigeon = new Pigeon();
System.out.println(“\n—– Pigeon Bird Details —–“);
pigeon.eating();
pigeon.flying();
// Here we create a Penguin object
Penguin penguin = new Penguin();
System.out.println(“\n—– Penguin Details —–“);
penguin.eating();
}
}
The main idea of the Liskov Substitution Concept Principle in Java.
- Here, in the Liskov Substitution Java concept, all child classes declared by the user must behave in the proper order with respect to their parent or root class.
I — Interface Segregation Principle (ISP) concept in Java.
The Interface Segregation Concept method in Java programs is that a class should not be forced to implement methods it does not need.
Instead of creating a large interface for a class, create a small, specialized class interface.
Example of a bad Interface Segregation Concept.
interface Worker {
void work();
void eat();
}
Here, let’s assume a robot implements it.
class Robot implements Worker {
public void work() {
System.out.println(“It’s Working”);
}
public void eat() {
// A robot, a machine, does not eat food.
}
}
Here, the Java user forces the robot, a machine, to implement an unnecessary task or method.
Example of a Better Interface Segregation Concept.
interface Workable {
void work();
}
interface Eatable {
void eat();
}
Here, the class Human implements Workable, Eatable {
public void work() {
System.out.println(“It’s Working”);
}
public void eat() {
System.out.println(“It’s Eating”);
}
}
class Robot implements Workable {
public void work() {
System.out.println(“It’s Working”);
}
}
Complete Example of Interface Segregation Principle (ISP) concept Principle.
// Here we set Interface 1: Defines all working behaviour
interface Workable {
void working();
}
// Here we set Interface 2: Defines all class eating behaviour
interface Eatable {
void eating();
}
// Here Man class implements both interfaces
class Man implements Workable, Eatable {
public void working() {
System.out.println(“Man is Working”);
}
public void eating() {
System.out.println(“Man is Eating”);
}
}
// Here the Robot class implements only with Workable interface not to other eating interface
class Robot implements Workable {
public void working() {
System.out.println(“Robot is Working”);
}
}
//Here we set Main class
public class Main {
public static void main(String[] args) {
//Here we create Man class object
Man man = new Man();
System.out.println(“—– Man Activities —–“);
man.working();
man.eating();
// Here we create Robot class object
Robot robot = new Robot();
System.out.println(“\n—– Robot Activities —–“);
robot.working();
}
}
The main idea of the Interface Segregation Principle (ISP) concept Principle in Java.
- Here, in the interface segregation example, priority is given to small, focused class interface objects rather than larger class interfaces.
D — Dependency Inversion Principle (DIP) concept in Java.
In a Java program, the Dependency Inversion Principal concept is that methods from a high-level module in a class should not be directly dependent on a low-level module class. Both of these classes should depend on abstraction class methods.
In general, do not tightly couple a user-defined class to a specific class implementation.
Example of a bad Dependency Inversion Principal concept.
class MySQLDatabase {
void save() {
System.out.println(“Data Save to MySQL”);
}
}
class UserService {
private MySQLDatabase database = new MySQLDatabase();
void saveUser() {
database.save();
}
}
In this example, UserService is tightly coupled to, or dependent on, the MySQLDatabase interface.
If the user here needs a PostgreSQL database, the user will have to manually modify the UserService.
Example of a Better Dependency Inversion Principal Concept.
Create an abstraction class method.
interface Database {
void save();
}
Implement this in a class.
class MySQLDatabase implements Database {
public void save() {
System.out.println(“Save data to MySQL”);
}
}
class PostgreSQLDatabase implements Database {
public void save() {
System.out.println(“Save data to PostgreSQL”);
}
}
Now let’s use a dependency injection method.
class UserService {
private database database;
UserService(Database database) {
this.database = database;
}
void saveUser() {
database.save();
}
}
Final use.
UserService service =
new UserService(new MySQLDatabase());
service.saveUser();
Now we can easily switch:
UserService service =
new UserService(new PostgreSQLDatabase());
Complete Example of Dependency Inversion Principle (DIP) concept Principle.
// Here we set Interface: Database abstraction class method
interface Database {
void save();
}
//Here MySQL Database implementation method
class MySQLDatabase implements Database {
public void save() {
System.out.println(“Save data to MySQL Database Software”);
}
}
// Here PostgreSQL Database implementation method
class PostgreSQLDatabase implements Database {
public void save() {
System.out.println(“Save data to PostgreSQL Database Software”);
}
}
// Here database UserService totally depends on above created Database interface
class UserService {
private database database;
// Here we define Constructor Dependency Injection method
UserService(Database database) {
this.database = database;
}
void saveUser() {
database.save();
}
}
// Here we define Main class
public class Main {
public static void main(String[] args) {
// Here we are using MySQL Database
System.out.println(“—– MySQL Database Update —–“);
UserService service1=
new UserService(new MySQLDatabase());
service1.saveUser();
// Here we are using PostgreSQL Database
System.out.println(“\n—– PostgreSQL Database Update —–“);
UserService service2=
new UserService(new PostgreSQLDatabase());
service2.saveUser();
}
}
The main idea of the Dependency Inversion Principle (DIP) concept in Java.
- In the Dependency Inversion Principal example, database users should not depend on concrete classes, but should depend entirely on interface/abstraction classes.
Main Use and Description of All 5 Solid Principal in One Table
| # | Principle | Detail Principal Name | Easy Implementation With |
| 1. | S | Single Responsibility | Single responsibility principal used with one class → one responsibility only method |
| 2. | O | Open/Closed | Open/closed principal used to extend without modifying its existing source code |
| 3. | L | Liskov Substitution | Liskov substitution principal used with child class should be usable as its parent class |
| 4. | I | Interface Segregation | Interface segregation principal keeps interfaces small and specific class element |
| 5. | D | Dependency Inversion | Dependency inversion principal depends on abstractions class method, not concrete classes |
Conclusion of Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion.
There’s an easy way to remember these 5 SOLID principles in Java:
- S → Use Single Responsibility in a single job class interface method.
- O → Use Open/Closed methods for open extensions.
- L → Use Liskov Substitution methods in the parent class.
- I → Use Interface Segregation methods to keep the interface small.
- D → Dependency Inversion Principles: Rely solely on the abstraction concept in the class.
These SOLID principles are essential concepts in Java, Spring Boot, and system/design interviews, as they indicate to Java users why they create classes, interfaces, and dependencies the way they do.

