1. Single Responsibility Principle (SRP)

Meaning:

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

Java Example:

Instead of a single class handling both data storage and data representation, you split these tasks into separate classes.

    // Combining responsibilities (not ideal)
    public class User {
        public void saveUserToDatabase() {/*...*/}
        public void displayUserDetails() {/*...*/}
    }

    // Split responsibilities (preferred)
    public class UserDatabase {
        public void saveUser(User user) {/*...*/}
    }

    public class UserDetailsRenderer {
        public void displayUserDetails(User user) {/*...*/}
    }

2. Open/Closed Principle (OCP)

Meaning:

Classes should be open for extension but closed for modification. You should be able to add new functionality without changing existing code.

Java Example:

By using interfaces or abstract classes, new functionality can be added without changing existing code.

    public interface Shape {
        double area();
    }

    public class Circle implements Shape {
        private double radius;
        public Circle(double radius) { this.radius = radius; }
        @Override
        public double area() { return Math.PI * radius * radius; }
    }

    public class Rectangle implements Shape {
        private double width, height;
        public Rectangle(double width, double height) { this.width = width; this.height = height; }
        @Override
        public double area() { return width * height; }
    }

3. Liskov Substitution Principle (LSP)

Meaning:

Objects of a superclass should be able to be replaced with objects of a subclass without affecting the correctness of the program.

Java Example:

Ensuring that overridden methods in subclasses maintain the “contract” set by the superclass.

    public class Bird {
        public void fly() {/*...*/}
    }

    public class Ostrich extends Bird {
        // An ostrich cannot fly, so overriding the fly method or throwing an exception would violate LSP.
    }

4. Interface Segregation Principle (ISP)

Meaning:

A class should not be forced to implement interfaces it doesn’t use. Instead of one large interface, several smaller, specific interfaces are better.

Java Example:

The example does all the talking here!

    // Instead of one large interface
    public interface Worker {
        void work();
        void eat();
    }

    // Use smaller, specific interfaces
    public interface Workable {
        void work();
    }

    public interface Eatable {
        void eat();
    }

5. Dependency Inversion Principle (DIP)

Meaning:

High-level modules (classes) should not depend on low-level modules. Both should depend on abstractions (interfaces or abstract classes).

Java Example:

Instead of a switch class directly depending on a light bulb, they both depend on an interface.

    public interface Switchable {
        void turnOn();
        void turnOff();
    }

    public class LightBulb implements Switchable {
        @Override
        public void turnOn() {/*...*/}
        @Override
        public void turnOff() {/*...*/}
    }

    public class Switch {
        private Switchable device;
        public Switch(Switchable device) { this.device = device; }
        // use device here
    }