The SOLID principles

Category : Microservices | Sub Category : Microservices | By Prasad Bonam Last updated: 2023-11-01 10:55:08 Viewed : 221


The SOLID principles:

The SOLID principles are a set of five design principles that help software developers create more maintainable, flexible, and understandable code. These principles can be applied to any object-oriented programming language, including Java. Here are the SOLID principles along with examples in Java:

  1. Single Responsibility Principle (SRP): A class should have only one reason to change.

    java
    // Example demonstrating Single Responsibility Principle class Order { public void calculateTotalPrice() { // calculate total price logic } public void printOrder() { // print order logic } }
  2. Open/Closed Principle (OCP): Software entities should be open for extension but closed for modification.

    java
    // Example demonstrating Open/Closed Principle interface Shape { double area(); } class Circle implements Shape { private double radius; public double area() { return Math.PI * radius * radius; } } class Rectangle implements Shape { private double length; private double width; public double area() { return length * width; } }
  3. Liskov Substitution Principle (LSP): Subtypes must be substitutable for their base types without altering the correctness of the program.

    java
    // Example demonstrating Liskov Substitution Principle class Vehicle { void startEngine() { // start engine logic } } class Car extends Vehicle { // additional car-specific functionality } class ElectricCar extends Vehicle { // additional electric car-specific functionality }
  4. The LSP states that objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program.

    In Java, you can apply the Liskov Substitution Principle by ensuring that a subclass can be substituted for its superclass without altering the desired behavior. Heres an example that demonstrates this principle:

    java
    class Vehicle { public void start() { System.out.println("Vehicle starting..."); } } class Car extends Vehicle { @Override public void start() { System.out.println("Car starting..."); } } class TestLSP { public static void main(String[] args) { Vehicle vehicle = new Car(); // LSP applied here vehicle.start(); // This should print "Car starting..." } }

    In the example above, the Car class is a subtype of the Vehicle class. The start method in the Car class overrides the start method in the Vehicle class, allowing the Car class to be substituted for its superclass Vehicle. The behavior of the program remains consistent, and the start method of the Car class is invoked as expected without any disruption.

    By following the Liskov Substitution Principle, you ensure that subclasses can be used interchangeably with their superclasses, enabling more flexible and modular designs in your Java applications. This principle helps create a more robust and maintainable codebase by promoting a strong and consistent inheritance hierarchy.

    Interface Segregation Principle (ISP): A client should not be forced to depend on methods it does not use.

    java
    // Example demonstrating Interface Segregation Principle interface Printer { void print(); } interface Scanner { void scan(); } class AllInOnePrinter implements Printer, Scanner { public void print() { // print functionality } public void scan() { // scan functionality } }
  5. The Interface Segregation Principle (ISP) is one of the five SOLID principles in object-oriented programming. It emphasizes that no client should be forced to depend on methods it does not use. The ISP encourages the creation of specific interfaces for clients, rather than one general-purpose interface, to avoid imposing unnecessary dependencies.

    In Java, you can apply the Interface Segregation Principle by designing cohesive and focused interfaces tailored to the specific needs of the clients that use them. Here is an example that demonstrates the application of the Interface Segregation Principle:

    java
    // Incorrect: Violating ISP interface Worker { void work(); void eat(); } class Engineer implements Worker { public void work() { System.out.println("Engineer is working"); } public void eat() { System.out.println("Engineer is eating"); } } class Robot implements Worker { public void work() { System.out.println("Robot is working"); } public void eat() { // This is not applicable to a robot and violates ISP throw new UnsupportedOperationException("Robots do not eat"); } }

    In the above example, the Worker interface includes the methods work and eat. However, the eat method is not applicable to all types of workers. The Robot class, which implements the Worker interface, does not have a need for the eat method, and its implementation throws an exception.

    To adhere to the Interface Segregation Principle, you can split the Worker interface into more specialized interfaces, as shown in the corrected example below:

    java
    // Correct: Following ISP interface Workable { void work(); } interface Eatable { void eat(); } class Engineer implements Workable, Eatable { public void work() { System.out.println("Engineer is working"); } public void eat() { System.out.println("Engineer is eating"); } } class Robot implements Workable { public void work() { System.out.println("Robot is working"); } }

    By segregating the Worker interface into the Workable and Eatable interfaces, the dependencies on methods that are not applicable to all implementing classes are eliminated, thereby promoting a more maintainable and cohesive design. Applying the Interface Segregation Principle helps create interfaces that are more specific and tailored to the requirements of the client classes, resulting in a more flexible and modular codebase.

    Dependency Inversion Principle (DIP): High-level modules should not depend on low-level modules. Both should depend on abstractions.

    java
    // Example demonstrating Dependency Inversion Principle interface MessageService { void sendMessage(String message); } class EmailService implements MessageService { public void sendMessage(String message) { // send message via email } } class Notification { private final MessageService messageService; public Notification(MessageService messageService) { this.messageService = messageService; } public void sendNotification(String message) { messageService.sendMessage(message); } }

By adhering to the SOLID principles, developers can create more maintainable, robust, and extensible Java applications that are easier to test and modify. Applying these principles can lead to better code quality and improved software design.


The SOLID principles are a set of five design principles that are commonly used in object-oriented programming to create maintainable, scalable, and understandable code. These principles are intended to make software more modular and flexible. Below, I will explain each of the SOLID principles and provide examples in Java.

  1. Single Responsibility Principle (SRP): This principle states that a class should have only one reason to change, meaning it should have only one responsibility.

    Example in Java:

    java
    // Incorrect: Violating SRP class Employee { public void calculateSalary() { // Calculate employees salary } public void saveToDatabase() { // Save employee data to the database } }

    In the above example, the Employee class violates the SRP by handling both salary calculation and database operations. It should be split into two classes, one for salary calculation and another for database operations.

  2. Open/Closed Principle (OCP): This principle states that software entities (classes, modules, functions) should be open for extension but closed for modification.

    Example in Java:

    java
    // Correct: Following OCP interface Shape { double area(); } class Circle implements Shape { private double radius; public Circle(double radius) { this.radius = radius; } public double area() { return Math.PI * radius * radius; } } class Rectangle implements Shape { private double width; private double height; public Rectangle(double width, double height) { this.width = width; this.height = height; } public double area() { return width * height; } }

    The Shape interface can be extended to support new shapes (e.g., triangles) without modifying existing code.

  3. Liskov Substitution Principle (LSP): This principle states that objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program.

    Example in Java:

    java
    // Correct: Following LSP class Bird { void fly() { System.out.println("Bird is flying"); } } class Sparrow extends Bird { void fly() { System.out.println("Sparrow is flying"); } }

    Code that works with a Bird should also work correctly with a Sparrow.

  4. Interface Segregation Principle (ISP): This principle states that no client should be forced to depend on methods it does not use. It is about creating specific interfaces for clients instead of one general-purpose interface.

    Example in Java:

    java
    // Incorrect: Violating ISP interface Worker { void work(); void eat(); } class Engineer implements Worker { public void work() { // Engineers work } public void eat() { // Engineers lunch break } }

    In this example, an Engineer is forced to implement the eat method, which is not relevant to all workers. It should be split into separate interfaces like Workable and Eatable.

  5. Dependency Inversion Principle (DIP): This principle states that high-level modules should not depend on low-level modules, but both should depend on abstractions. It promotes using interfaces or abstract classes to decouple classes.

    Example in Java:

    java
    // Correct: Following DIP interface Switchable { void turnOn(); void turnOff(); } class LightBulb implements Switchable { public void turnOn() { // Turn on the light bulb } public void turnOff() { // Turn off the light bulb } }

    Code depending on a Switchable interface can work with various switchable devices like LightBulb without being tightly coupled to specific implementations.

Implementing these SOLID principles in your Java code can lead to more modular, maintainable, and extensible software, which is essential when building microservices or any other software that needs to evolve and adapt over time.

Search
Related Articles

Leave a Comment: