Mastering SOLID Principles in Software Design

The SOLID principles are a set of design principles in object-oriented programming aimed at creating more understandable, flexible, and maintainable software. The acronym SOLID stands for:

  1. S: Single Responsibility Principle (SRP)
  2. O: Open/Closed Principle (OCP)
  3. L: Liskov Substitution Principle (LSP)
  4. I: Interface Segregation Principle (ISP)
  5. D: Dependency Inversion Principle (DIP)

1. Single Responsibility Principle (SRP)

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

// BAD Example
class Report {
    public void generateReport() {
        /*...*/
    }
    public void printReport() {
        /*...*/
    }
    public void saveToFile() {
        /*...*/
    }
}
// GOOD Example
class ReportGenerator {
    public void generateReport() {
        /*...*/
    }
}
class ReportPrinter {
    public void printReport() {
        /*...*/
    }
}
class ReportSaver {
    public void saveToFile() {
        /*...*/
    }
}

2. Open/Closed Principle (OCP)

Definition: Software entities (classes, modules, functions) should be open for extension but closed for modification.

// BAD Example
class Discount {
    public double getDiscount(String customerType) {
        if (customerType.equals("Premium")) {
            return 0.2;
        }
        return 0.1;
    }
}
// GOOD Example
interface DiscountStrategy {
    double getDiscount();
}
class PremiumDiscount implements DiscountStrategy {
    public double getDiscount() {
        return 0.2;
    }
}
class RegularDiscount implements DiscountStrategy {
    public double getDiscount() {
        return 0.1;
    }
}

3. Liskov Substitution Principle (LSP)

Definition: Subtypes must be substitutable for their base types without altering the correctness of the program.

// BAD Example
class Bird {
    public void fly() {}
}
class Ostrich extends Bird {
    public void fly() {
        throw new UnsupportedOperationException();
    }
}
// GOOD Example
interface Bird {}
interface FlyingBird extends Bird {
    void fly();
}
class Sparrow implements FlyingBird {
    public void fly() {
        /*...*/
    }
}
class Ostrich implements Bird {}

        

4. Interface Segregation Principle (ISP)

Definition: Clients should not be forced to depend on interfaces they do not use.

// BAD Example
interface Worker {
    void work();
    void eat();
}
class Robot implements Worker {
    public void work() {
        /*...*/
    }

    public void eat() {
        /*Does not apply*/
    }
}
// GOOD Example
interface Workable {
    void work();
}
interface Eatable {
    void eat();
}
class Human implements Workable, Eatable {
    public void work() {
        /*...*/
    }

    public void eat() {
        /*...*/
    }
}
class Robot implements Workable {
    public void work() {
        /*...*/
    }
}

5. Dependency Inversion Principle (DIP)

Definition: High-level modules should not depend on low-level modules. Both should depend on abstractions.

// BAD Example
class LightBulb {
    public void turnOn() {}
    public void turnOff() {}
}
class Switch {
    private LightBulb bulb = new LightBulb();

    public void operate() {
        bulb.turnOn();
    }
}
// GOOD Example
interface Switchable {
    void turnOn();
    void turnOff();
}
class LightBulb implements Switchable {
    public void turnOn() {}
    public void turnOff() {}
}
class Switch {
    private Switchable device;

    public Switch(Switchable device) {
        this.device = device;
    }
    public void operate() {
        device.turnOn();
    }
}       

Conclusion

Adopting the SOLID principles helps in building clean, maintainable, and scalable object-oriented systems. These principles are foundational to good software design and are essential for writing robust code.

Up Next
    Ebook Download
    View all
    Learn
    View all