SOLID PRINCIPLES
[Link] is Solid Principles?
The solid Principles are Five Fundamental Design Principles that help
create maintainable, scalable and robust software.
Why should you follow solid?
[Link] Maintenance :
Code is easier to debug , extend and modify
[Link] Scalability :
Adding new features doesn't break existing functionality
[Link] Testability :
Writing Unit tests become easier
[Link] Coupling :
Components can be replaced immediately
[Link] RESPONSIBILITY PRINCIPLE :
● Each software module or class should have only one reason to
change
● Each class should have only one responsibility or purpose
●
Bad Example (Violates SRP) :
The Employee class does too many things:
1. Stores employee details.
[Link] employee salary
3. Saves employee details to a database.
Problem:
If we need to change the salary calculation, we might also affect
database operations, breaking SRP.
Good Example (Follows SRP) :
We split responsibilities into separate classes:
[Link] Stores employee details.
[Link] Handles salary calculations.\
[Link] Saves data to the database.
Why is This Better?
If we need to change salary calculations, we only modify SalaryCalculator.
If we switch to a different database, we only modify EmployeeRepository.
The code is easier to maintain and test.
[Link]/CLOSED PRINCIPLE :
● A class should be open for extension but closed for modification.
● This means you should not modify existing code when adding new
functionality. Instead, you extend the behavior using abstraction
(interfaces or inheritance).
Bad Example (Violates OCP):
Imagine we have a Shape class that calculates the area for circles and
rectangles. Now, if we add a Triangle, we must modify the CalculateArea
method.
Problem:
If we add a Triangle, we must modify the class, which breaks OCP.
If multiple developers work on the file, this can lead to bugs and conflicts.
Good Example (Follows OCP) :
Instead of modifying the existing class, we create a base class (Shape) and
extend it when adding new shapes.
Advantage:
If we need to add a Triangle, we don’t modify existing code, we just create
a new class:
[Link] SUBSTITUTION PRINCIPLE :
● The object of derived class should be able to replace an object of
the base class without causing errors in the system or modifying the
behaviour of the base class
● A subclass should be able to replace its parent class without breaking
the functionality.
Bad Example (Violates LSP) :
Consider a Bird class with a Fly() method. Now, Penguins cannot fly,
but they inherit Fly(), which leads to an error.
Problem:
● Penguin inherits Fly(), but throws an exception instead of
behaving like other birds.
● This breaks LSP because now Bird objects cannot always be
replaced with Penguin.
Good Example : (Following LSP )
We fix this by separating flying and non-flying birds.
Now, Penguin does not inherit Fly(), and we don’t break LSP!
[Link] Segregation Principle (ISP) :
● Clients should not be forced to depend on interfaces they do not use
● A single large interface should be split into multiple small interface to
prevent unnecessary dependencies
Bad Example (Violates ISP) :
Here, the IWorker interface forces both humans and robots to
implement Eat(), even though robots don’t eat.
Problem:
● RobotWorker is forced to implement Eat(), which makes no
sense.
● Violates ISP because the interface includes unrelated behaviors.
Good Example : (Following ISP)
Instead of one large interface, we create smaller, specific interfaces.
Now, Robot does not have an unnecessary Eat() method, and we
follow ISP!
[Link] Inversion Principle (DIP) :
● High-level modules (business logic) should not depend on low-level
modules (data access).
● Both should depend on abstractions (interfaces).
● This makes the code flexible, testable, and loosely coupled.
Bad Example (Violates DIP) :
Problem Without DIP (Tightly Coupled Code)
Let's say we have a UserService that depends directly on
EmailNotification.
Problem:
● If we want to switch to SMS notifications, we must modify
UserService, which violates DIP.
● The UserService is tightly coupled to EmailNotification,
making changes difficult.
Good Example : (Follows DIP) :
Solution With DIP (Loosely Coupled Code)
We introduce an interface (INotification) and let UserService
depend on this abstraction, not a specific notification method.
Why is This Better?
Loose Coupling – UserService
does not depend on a specific notification method.
Easily Extendable – We can add PushNotification without
modifying UserService
.
Better Testability – We can mock INotification in unit tests.
SUMMARY :
SRP – One class, one responsibility.
OCP – Extend without modifying existing code.
LSP – Subclasses should not break parent behavior.
ISP – No unnecessary method implementations.
DIP – Depend on abstractions, not concrete classes.
🔥 Final Thought: Why SOLID Matters?
Easier to maintain
– Changes in one part don’t break everything.
Better scalability
– Easily add new features without modifying old code.
Improved testability
– Mock dependencies and write better unit tests.
Loose coupling – Components are independent and reusable.