SOLID Principles

Ā 

1. Single Responsibility Principle (SRP)

Definition: A class should have only one reason to change, meaning it should do only one thing (one responsibility).
Problem: Classes that handle multiple responsibilities become large, hard to understand, and more likely to break when changes are made.
Solution: Split functionalities into smaller, focused classes — each handling one specific concern.


Example: Instead of one InvoiceManager handling invoice calculation, printing, and email sending, split it into InvoiceCalculator, InvoicePrinter, and InvoiceEmailer.


2. Open/Closed Principle (OCP)

Definition: Software entities should be open for extension, but closed for modification.
Problem: Adding new functionality often requires modifying existing code, risking bugs in stable code.
Solution: Design code to be extended via inheritance, interfaces, or composition, without changing existing tested logic.


Example: A payment system that supports new payment methods (credit card, PayPal) by adding new classes without changing the core payment processing class.


3. Liskov Substitution Principle (LSP)

Definition: Objects of a superclass should be replaceable with objects of its subclass without breaking the application.
Problem: Subclasses sometimes override behavior in ways that violate expectations, causing runtime errors or incorrect results.
Solution: Ensure subclasses follow the contract defined by their parent classes — no unexpected behavior changes.


Example: If Bird has a method fly(), then Penguin (which cannot fly) should not inherit from Bird in a way that breaks fly().


4. Interface Segregation Principle (ISP)

Definition: Clients should not be forced to depend on interfaces they do not use.
Problem: Large, "fat" interfaces force implementing classes to write empty or irrelevant methods.
Solution: Break large interfaces into smaller, more specific ones.


Example: Instead of one IMachine interface with print(), scan(), and fax(), create separate IPrinter, IScanner, and IFax interfaces.


5. Dependency Inversion Principle (DIP)

Definition: High-level modules should not depend on low-level modules — both should depend on abstractions.
Problem: Code tightly coupled to concrete implementations is hard to change or test.
Solution: Depend on interfaces or abstract classes; use dependency injection to provide implementations.


Example: A ReportGenerator should depend on an IReportFormatter interface, not directly on a PDFReportFormatter class.


šŸ’” In summary:

  • S – One class, one job.
  • O – Extend without changing existing code.
  • L – Subclasses must honor parent behavior.
  • I – Keep interfaces focused.
  • D – Depend on abstractions, not concrete classes.
Back to blog

Leave a comment

Please note, comments need to be approved before they are published.