System Design ( Day - 41 )

Manoj KumarManoj Kumar
3 min read

SOLID Principles | Revision

๐Ÿ˜ฉ Why Problems Arise Without SOLID Principles?

Without SOLID, you'll face:

  • โŒ Poor maintainability

  • โŒ Less readability

  • โŒ Higher chances of bugs

  • โŒ Tightly coupled classes

  • โŒ Difficult testing and refactoring


๐Ÿงฑ What is SOLID?

SOLID is an acronym representing 5 principles that help build maintainable and scalable software:

PrincipleName
SSingle Responsibility Principle (SRP)
OOpen-Closed Principle (OCP)
LLiskov Substitution Principle (LSP)
IInterface Segregation Principle (ISP)
DDependency Inversion Principle (DIP)

๐Ÿ”น S โ€” Single Responsibility Principle (SRP)

๐Ÿ’ฌ Definition: A class should have only one reason to change.

๐Ÿ“บ Analogy: A TV remote should control only the TV โ€” not your AC or refrigerator!

๐Ÿ“Œ Problem: If a class does multiple things, modifying one part can unintentionally break the others.

๐Ÿ› ๏ธ Solution: Separate responsibilities into their own classes.

javaCopyEdit// โŒ Bad
class Remote {
    controlTV();
    controlAC(); // Not its job
}

// โœ… Good
class TVRemote {
    controlTV();
}

class ACRemote {
    controlAC();
}

๐Ÿ”น O โ€” Open-Closed Principle (OCP)

๐Ÿ’ฌ Definition: Software entities should be open for extension but closed for modification.

๐Ÿ“ฆ Real-world: Suppose you have a SaveToSQL() method. Tomorrow you want to save data to MongoDB or File too. Don't touch the original logic โ€” just extend it!

๐Ÿ› ๏ธ Solution: Use interfaces and polymorphism to extend behavior.

javaCopyEditabstract class DataSaver {
    abstract void save(Data data);
}

class SaveToSQL extends DataSaver {
    void save(Data data) {
        // Save to SQL
    }
}

class SaveToMongo extends DataSaver {
    void save(Data data) {
        // Save to MongoDB
    }
}

๐Ÿ”น L โ€” Liskov Substitution Principle (LSP)

๐Ÿ’ฌ Definition: Subclasses should be substitutable for their parent classes.

๐Ÿฆ Example:

  • Transaction class has deposit() and withdraw().

  • SavingsAccount & CurrentAccount follow both.

  • FixedDepositAccount supports only deposit().

โŒ Violating LSP:

javaCopyEditclass FixedDeposit extends Transaction {
    void withdraw() {
        throw new UnsupportedOperationException();
    }
}

โœ… Solution: Break them into multiple abstract classes:

javaCopyEditabstract class NonWithdrawableAccount {
    abstract void deposit();
}

abstract class WithdrawableAccount extends NonWithdrawableAccount {
    abstract void withdraw();
}

Now inherit WithdrawableAccount in SavingsAccount & CurrentAccount,
and NonWithdrawableAccount in FixedDeposit.


๐Ÿ”น I โ€” Interface Segregation Principle (ISP)

๐Ÿ’ฌ Definition: Clients should not be forced to depend on methods they do not use.

๐Ÿ–จ๏ธ Example:

โŒ Violating ISP:

javaCopyEditinterface Shape {
    double area();
    double volume(); // Not needed for 2D shapes
}

class Square implements Shape {
    double area() { ... }
    double volume() { throw new UnsupportedOperationException(); }
}

โœ… Refactor into segregated interfaces:

javaCopyEditinterface TwoDShape { double area(); }
interface ThreeDShape extends TwoDShape { double volume(); }

class Square implements TwoDShape {
    double area() { ... }
}

class Cube implements ThreeDShape {
    double area() { ... }
    double volume() { ... }
}

๐Ÿง  Benefit: Clean, focused contracts.


๐Ÿ”น D โ€” Dependency Inversion Principle (DIP)

๐Ÿ’ฌ Definition: High-level modules should not depend on low-level modules. Both should depend on abstractions.

๐Ÿ“ง Example:
High-level class AuthService should not depend directly on EmailSender.

โŒ Violation:

javaCopyEditclass AuthService {
    EmailSender sender = new EmailSender();

    void register(User user) {
        sender.sendWelcomeEmail(user.email);
    }
}

โœ… Apply DIP:

javaCopyEditinterface MessageSender {
    void send(String to);
}

class EmailSender implements MessageSender {
    public void send(String to) { ... }
}

class AuthService {
    MessageSender sender;

    AuthService(MessageSender sender) {
        this.sender = sender;
    }

    void register(User user) {
        sender.send(user.email);
    }
}

๐Ÿง  Benefit: Easily switch between EmailSender, SMSSender, PushNotifier, etc.

0
Subscribe to my newsletter

Read articles from Manoj Kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Manoj Kumar
Manoj Kumar