DEV Community

Code Green
Code Green

Posted on

SOLID Principles in Java with Examples

SOLID Principles in Java

SOLID is an acronym that represents five design principles aimed at making software designs more understandable, flexible, and maintainable. These principles are particularly important in object-oriented programming, such as Java.

1. Single Responsibility Principle (SRP)

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

Real-World Example:

    class Report {
        public void generateReport() {
            // Code to generate report
        }
    }

    class ReportPrinter {
        public void printReport(Report report) {
            // Code to print report
        }
    }
Enter fullscreen mode Exit fullscreen mode

In this example, the Report class is responsible for generating reports, while the ReportPrinter class handles printing. This separation of concerns makes the code easier to maintain.

2. Open/Closed Principle (OCP)

Software entities should be open for extension but closed for modification. This means you can add new functionality without changing existing code.

Real-World Example:

    interface Shape {
        double area();
    }

    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;
        }
    }

    class Circle implements Shape {
        private double radius;

        public Circle(double radius) {
            this.radius = radius;
        }

        public double area() {
            return Math.PI * radius * radius;
        }
    }
Enter fullscreen mode Exit fullscreen mode

You can add new shapes like Triangle without modifying existing shape classes, adhering to the Open/Closed Principle.

3. Liskov Substitution Principle (LSP)

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

Real-World Example:

    class Bird {
        public void fly() {
            // Code for flying
        }
    }

    class Sparrow extends Bird {}

    class Ostrich extends Bird { 
       @Override
       public void fly() { 
           throw new UnsupportedOperationException("Ostriches can't fly");
       }
    }
Enter fullscreen mode Exit fullscreen mode

The Ostrich class violates LSP because it cannot fly like its superclass. A better design would separate flying and non-flying birds.

4. Interface Segregation Principle (ISP)

No client should be forced to depend on methods it does not use. This principle encourages creating smaller, more specific interfaces.

Real-World Example:

    interface Printer {
        void print();
    }

    interface Scanner {
        void scan();
    }

    class MultiFunctionPrinter implements Printer, Scanner {
       public void print() { /* Printing logic */ }
       public void scan() { /* Scanning logic */ }
    }
Enter fullscreen mode Exit fullscreen mode

The interfaces are segregated so that clients only implement what they need. A simple printer wouldn't need scanning functionality.

5. Dependency Inversion Principle (DIP)

High-level modules should not depend on low-level modules; both should depend on abstractions. Abstractions should not depend on details; details should depend on abstractions.

Real-World Example:

    interface NotificationService {
       void sendNotification(String message);
    }

    class EmailService implements NotificationService {
       public void sendNotification(String message) {
           // Send email notification
       }
    }

    class User {
       private NotificationService notificationService;

       public User(NotificationService notificationService) {
           this.notificationService = notificationService;
       }

       public void notifyUser(String message) {
           notificationService.sendNotification(message);
       }
    }
Enter fullscreen mode Exit fullscreen mode

The User class depends on the abstraction of NotificationService rather than a concrete implementation like EmailService. This allows for easy swapping of notification methods.

Conclusion

The SOLID principles are essential for creating maintainable and scalable software in Java. By following these principles, developers can ensure that their code is well-structured and adaptable to change over time.

Top comments (0)