There are numerous design rules, patterns, or concepts in the area of object-oriented programming (OOP). SOLID Principles in Java stands for five of these ideas. While each of these five principles represents a different concept, they also overlap to the point where accepting one implies or leads to accepting the others.
In this tutorial, we will go through the SOLID principles in Java, their explanation with examples, and numerous reasons to adopt them.
What is SOLID?
SOLID in Java is an abbreviation for a collection of techniques that, when combined, make code more adaptable to change. These ideas were introduced by Bob Martin and Micah Martin in their book 'Agile Principles, Patterns, and Practices'.
SOLID principles serve as the foundation for developing object-oriented applications that are flexible, adaptable, and maintainable. These principles also constitute a language that can be used in discussions with other team members or as part of community-shared technical documentation.
The acronym SOLID stands for:
Single Responsibility Principle (SRP)
Open-Closed Principle (OCP)
Liskov Substitution Principle (LSP)
Interface Segregation Principle (ISP)
Dependency Inversion Principle (DIP)
Single Responsibility Principle
According to the single responsibility concept, each Java class must perform a single function. Implementing numerous functionalities in a single class mashes up the code, and any changes may affect the entire class. The code is clear and straightforward to maintain. Let's look at an example of the single responsibility principle.
Example of Single Responsibility Principle
There are several classes in all prominent Java libraries that correspond to the single responsibility principle. In Log4j2, for example, we have separate classes with logging methods, other classes with logging levels, and so on.
In the given example, we have two classes: Person and Account. Both have a single responsibility to store their specific information. If we want to alter the status of a Person, we don't need to change the class Account, and vice versa.
public class Person {
private Long person_Id;
private String first_Name;
private String last_Name;
private String age;
private List<Account> accounts;
}
Open-Closed Principle
According to the Open Closed Principle, software components should be open for extension but closed for modification. It means that the application classes should be structured in such a way that if other developers want to change the flow of control in specific scenarios in the application, they only need to extend the class and override some functions.
If other developers are unable to write the desired behavior due to class limitations, we should examine refactoring the class. It doesn’t mean that anyone can change the entire logic of the class, but that one should be able to override the software's settings in a nonharmful fashion that the software allows.
Example of Open-Closed Principle
Assume that Vehicle_Info is a class with the function vehicle_Number(), which returns the vehicle number. If we wish to add another Truck subclass, we simply add another if statement that violates the open-closed concept. The only way to add the subclass and achieve the principle's aim is to override the vehicleNumber() method, as illustrated below:
public class Vehicle_Info
{
public int vehicle_Number()
{
//functionality
}
}
public class Car extends Vehicle_Info
{
public int vehicle_Number()
{
return this.get_Value();
}
public class Car extends Truck
{
public int vehicle_Number()
{
return this.get_Value();
}
Liskov Substitution Principle
The Liskov Substitution Principle (LSP) was introduced by Barbara Liskov. It pertains to inheritance in the sense that derived classes must be totally interchangeable with their base classes. In other words, if class A is a subtype of class B, we should be able to substitute B with A without disrupting the program's behavior.
It broadens the open-close principle by concentrating on the behavior of a superclass and its subtypes. Unless there is a compelling reason to do otherwise, you should build the classes to preserve the attribute.
Example of Liskov Substitution Principle
The below classes in the example violated the Liskov substitution principle because the Student_BMI class had additional limitations, such as height and weight being the same. As a result, the Student class (base class) cannot be replaced by the Student_BMI class (derived class). As a result, replacing the class Student with the StudentBMI class may result in unexpected behavior.
public class Student
{
private int height;
private int weight;
public void set_Height(int h)
{
height = h;
}
public void set_Weight(int w)
{
weight= w;
}
// Other Code
}
public class Student_BMI extends Student
{
public void set_Height(int h)
{
super.set_Height(h);
super.set_Weight(w);
}
public void set_Weight(int h)
{
super.set_Height(h);
super.set_Weight(w);
}
}
Interface Segregation Principle
According to this principle, larger interfaces break into smaller ones. Since the implementation classes only use the necessary methods, you should not force clients to use methods they do not wish to employ. The interface segregation principle's purpose is comparable to the single responsibility principle.
Example of Interface Segregation Principle
Java AWT event handlers for managing GUI events fired by the keyboard and mouse are the best place to search for Interface Segregation Principle examples. Each type of event has different listener classes. Only handlers for events that we want to manage are required. Nothing is required.
public class MouseMotionListenerImpl implements MouseMotionListener
{
@Override
public void mouse_Dragged(MouseEvent e) {
//handler code
}
@Override
public void mouse_Moved(MouseEvent e) {
//handler code
}
}
Dependency Inversion Principle
The principle states that abstraction (abstract classes and interfaces) should be used instead of specific implementations. High-level modules should not be dependent on low-level modules but rather on abstraction. Since abstraction is independent of detail, whereas detail is dependent on abstraction. It separates the program.
Example of Dependency Inversion Principle
In the example given below, the Student class requires an Address object and is in charge of initializing and using the Address object. If the Address class is updated in the future, we must likewise alter the Student class. This results in a close relationship between the Student and Address objects. The dependency inversion design technique can be used to tackle this problem.
public class Student
{
private Address add;
public Student()
{
add = new Address();
}
}
Why shall we use SOLID Principles in Java?
It minimizes dependencies so that a piece of code can be modified without affecting the rest of the code.
The principles are meant to make design simpler and more clear.
The system is maintainable, testable, scalable, and reusable as a result of the principles.
It avoids the software's poor design.
Benefits of Using SOLID Principles
SOLID principles ensure that the code is clean and consistent.
The code you write becomes more manageable and easy to maintain with the help of SOLID principles.
SOLID principles avoid the use of unnecessary code.
SOLID principles make code simple and readable.
By removing dependencies, code becomes self-contained.
Frequently Asked Questions
What is SOLID principles in Java?
SOLID is a set of design principles in Java and other object-oriented languages:
Single Responsibility
Open/Closed
Liskov Substitution
Interface Segregation
Dependency Inversion They promote clean, maintainable, and extensible code.
What are the 4 SOLID principles of Java?
The four SOLID principles in Java are:
Single Responsibility Principle (SRP)
Open/Closed Principle (OCP)
Liskov Substitution Principle (LSP)
Interface Segregation Principle (ISP)
How to practice SOLID principles in Java?
To practice SOLID principles in Java, follow these steps:
Understand the principles (SRP, OCP, LSP, ISP, DIP).
Apply them during class and interface design.
Refactor existing code to adhere to SOLID.
Use design patterns to support SOLID principles.
What are SOLID principles in OOP?
SOLID principles in Object-Oriented Programming are a set of guidelines to create maintainable, flexible, and robust software. They include Single Responsibility (SRP), Open/Closed (OCP), Liskov Substitution (LSP), Interface Segregation (ISP), and Dependency Inversion (DIP).
Conclusion
SOLID is a design methodology that ensures your program is modular, comprehensible, debuggable, and refactorable. Following SOLID principles in Java saves developers and maintainers time and effort in both development and maintenance. In this article, we discussed SOLID principles in Java and their complete explanation along with examples.
Head over to our practice platform, CodeStudio, to practice top problems, attempt mock tests, read interview experiences and interview bundles, followguided paths for placement preparations, and much more!