SOLID Principles (Part 2 - ISP, DIP)
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)
- 1Step 1
Suppose you have a
NotificationService(High-level) that sends alerts viaSmtpClient(Low-level). Initially, the service might instantiate the client directly:new SmtpClient(). - 2Step 2
Define an interface,
IMessageSender, with asend(string message)method. Both the high-level service and the low-level client will now depend on this interface. - 3Step 3
Modify the
NotificationServiceconstructor to accept anIMessageSenderinstead of creating one. This is 'Constructor Injection'. - 4Step 4
At the start of your application, you decide which concrete implementation to 'inject'. You can easily swap
SmtpSenderforSmsSenderwithout touching a single line of code in theNotificationService.
Summary of SOLID
| Principle | Key Takeaway |
|---|---|
| SRP | One class = One responsibility. |
| OCP | Add new code, don't change old code. |
| LSP | Subclasses must be perfect stand-ins for parents. |
| ISP | Keep interfaces small and specific. |
| DIP | Depend 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
Which principle suggests that it is better to have five specific interfaces than one massive 'God' interface?