CHAPTER 03
Intermediate
SOLID Principles
Updated: May 16, 2026
30 min read
# CHAPTER 3
SOLID Principles
1. Introduction
You can know everything about OOP—classes, interfaces, and polymorphism—and still write terrible, unmaintainable code. Creating 5,000-line "God Classes" that handle databases, emails, and UI rendering simultaneously is technically valid OOP, but it is an architectural nightmare. To write clean, enterprise-grade code, developers rely on the SOLID Principles. Introduced by Robert C. Martin (Uncle Bob), these five design principles are the absolute standard for creating software that is easy to maintain, understand, and extend. Every Design Pattern you will learn is simply an application of these SOLID rules. In this chapter, we will master the five principles and learn how to refactor messy code into elegant architecture.2. Learning Objectives
By the end of this chapter, you will be able to:- Define all five SOLID principles (SRP, OCP, LSP, ISP, DIP).
- Refactor a "God Class" using the Single Responsibility Principle.
- Design extensible systems using the Open/Closed Principle.
- Understand the danger of violating the Liskov Substitution Principle.
- Apply Dependency Inversion to decouple high-level logic from low-level modules.
3. S - Single Responsibility Principle (SRP)
"A class should have one, and only one, reason to change."-
The Anti-Pattern: A
Userclass that holds the user's name, connects to the MySQL database to save the user, and sends a "Welcome" email. This class has three responsibilities. If the database changes, or the email API changes, this class must be rewritten.
-
The Solution: Split it up. Create a
Userclass (holds data), aUserRepositoryclass (handles the database), and aUserMailerclass (handles emails). Now, each class has only one job.
4. O - Open/Closed Principle (OCP)
"Software entities (classes, modules, functions) should be open for extension, but closed for modification."-
The Anti-Pattern: A
ShippingCalculatorclass with a massiveif/elseblock:if (type == 'ground') return 5; else if (type == 'air') return 20;. Every time you add a new shipping method, you have to modify this existing, tested class, risking breaking old code.
-
The Solution: Create a
ShippingStrategyinterface. Create separate classesGroundShippingandAirShippingthat implement the interface. The Calculator just accepts the interface. To addDroneShipping, you write a *new* class. You *extended* the system without *modifying* the Calculator class.
5. L - Liskov Substitution Principle (LSP)
"Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program."- The Concept: If Class B extends Class A, you should be able to pass Class B into any function that expects Class A, and the program should not crash or behave weirdly.
-
The Anti-Pattern: A
Birdclass has afly()method. APenguinclass extendsBird. But penguins can't fly, so thePenguin->fly()method throws an Exception. You have violated LSP, because a Penguin cannot truly substitute a Bird.
-
The Solution: Refactor the hierarchy. Create a
FlyingBirdinterface and only have Eagles and Sparrows implement it.
6. I - Interface Segregation Principle (ISP)
"Many client-specific interfaces are better than one general-purpose interface."-
The Anti-Pattern: A massive
Workerinterface withwork(),eat(), andsleep()methods. AHumanWorkerimplements it perfectly. ARobotWorkerimplements it, but is forced to write empty, uselesseat()andsleep()methods because robots don't eat.
-
The Solution: Break the fat interface into smaller ones:
Workable,Eatable,Sleepable. TheHumanimplements all three. TheRobotonly implementsWorkable.
7. D - Dependency Inversion Principle (DIP)
"Depend upon abstractions, not concretions."-
The Anti-Pattern: A high-level
OrderProcessorclass directly instantiates a low-levelMySQLDatabaseclass inside its constructor using thenewkeyword. The OrderProcessor is now permanently glued to MySQL.
-
The Solution: The
OrderProcessorshould accept aDatabaseInterfacethrough its constructor (Dependency Injection). You pass the MySQL class *into* the processor from the outside. Later, you can easily pass in aMongoDBDatabaseclass instead, and the OrderProcessor won't even notice.
8. Code Examples: Refactoring SRP
*Before (Violating SRP):*
php
*After (Applying SRP):*
php
9. Best Practices
- Pragmatism over Dogma: Writing perfectly SOLID code often means creating 5 files instead of 1. For a massive enterprise app, this modularity is mandatory. For a tiny, 100-line script, strictly adhering to SOLID might be massive overkill. Apply the principles where complexity demands it.
10. Mini Project: SOLID Refactoring
-
1.
The Scenario: You inherit a
ReportGeneratorclass. It fetches data from an API, formats it as JSON, and writes it to a local file. It violates SRP, OCP, and DIP.
- 2. The Refactor:
-
Create a
DataFetcherinterface (DIP).
-
Create a
Formatterinterface with aformat()method. ImplementJsonFormatterandXmlFormatter(OCP).
-
Create a
FileWriterclass (SRP).
-
Inject these dependencies into the
ReportGeneratorconstructor.
11. Practice Exercises
- 1. Define the Single Responsibility Principle (SRP). Why is a class that handles both business logic and database queries a violation of this principle?
- 2. Explain the Dependency Inversion Principle (DIP). How does "injecting" dependencies via the constructor make a class significantly easier to Unit Test?
12. MCQs with Answers
Question 1
A developer needs to add a new "Bitcoin" payment method to an application. Instead of editing the existing PaymentProcessor class to add an if (type == 'bitcoin') statement, they create a new BitcoinPayment class that implements a PaymentInterface. Which SOLID principle did they successfully apply?
Question 2
Which principle states that a high-level module (like a Checkout system) should not directly instantiate and depend on a low-level concrete class (like a Stripe API library), but should instead depend on an abstraction (like a PaymentGateway Interface)?
13. Interview Questions
- Q: Explain the Liskov Substitution Principle using the classic "Square/Rectangle" problem. Why does making a Square inherit from a Rectangle often violate LSP?
- Q: What is the Interface Segregation Principle? Walk me through a scenario where forcing a class to implement a "fat" interface leads to bad architectural design.
- Q: How do the SOLID principles directly relate to the Gang of Four Design Patterns? (Hint: Patterns are just standardized implementations of these principles).