Coursify

Mastering Low Level Design (LLD)

SOLID Principles (Part 2 - ISP, DIP)

20 mins

Finalize your SOLID foundation by learning about Interface Segregation and Dependency Inversion, the key to building truly decoupled and testable systems.

Learning Goals

  • Deconstruct 'fat' interfaces into lean, specific contracts (ISP).
  • Apply Dependency Inversion to decouple business logic from infrastructure (DIP).
  • Implement Constructor Injection as a practical implementation of DIP.

SOLID Principles (Part 2): ISP and DIP

In this final section on SOLID, we explore the Interface Segregation and Dependency Inversion principles.

4. Interface Segregation Principle (ISP)

"Clients should not be forced to depend upon interfaces that they do not use."

It is better to have many small, specific interfaces than one large, general-purpose "fat" interface.

Violation Example

Imagine an IMultiFunctionDevice interface with print(), scan(), and fax(). If you have a simple EconomicPrinter class, you are forced to implement scan() and fax(), even if they do nothing.

Correction: Split the interface into IPrinter, IScanner, and IFax. A high-end machine can implement all three, while a simple printer only implements IPrinter.

5. Dependency Inversion Principle (DIP)

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

DIP is the foundation of Dependency Injection. It ensures that your business logic (high-level) isn't tightly coupled to specific infrastructure (low-level) like databases or external APIs.

Implementing Dependency Injection (DIP)

  1. 1
    Step 1

    Suppose you have a NotificationService (High-level) that sends alerts via SmtpClient (Low-level). Initially, the service might instantiate the client directly: new SmtpClient().

  2. 2
    Step 2

    Define an interface, IMessageSender, with a send(string message) method. Both the high-level service and the low-level client will now depend on this interface.

  3. 3
    Step 3

    Modify the NotificationService constructor to accept an IMessageSender instead of creating one. This is 'Constructor Injection'.

  4. 4
    Step 4

    At the start of your application, you decide which concrete implementation to 'inject'. You can easily swap SmtpSender for SmsSender without touching a single line of code in the NotificationService.

Summary of SOLID

PrincipleKey Takeaway
SRPOne class = One responsibility.
OCPAdd new code, don't change old code.
LSPSubclasses must be perfect stand-ins for parents.
ISPKeep interfaces small and specific.
DIPDepend on interfaces, not concrete classes.

By adhering to SOLID, you move from "fragile" code that breaks on every change to "robust" code that grows gracefully.

Knowledge Check

Question 1 of 3
Q1Single choice

Which principle suggests that it is better to have five specific interfaces than one massive 'God' interface?