SOLID PRINCIPLES
1.What is Solid Principles?
The solid Principles are Five Fundamental Design Principles that help
create maintainable, scalable and robust software.
Why should you follow solid?
1.Easier Maintenance :
Code is easier to debug , extend and modify
2.Better Scalability :
Adding new features doesn't break existing functionality
3.Improve Testability :
Writing Unit tests become easier
4.Loose Coupling :
Components can be replaced immediately
1.SINGLE 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.
2.Calculates 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:
1.Employee Stores employee details.
2.SalaryCalculator Handles salary calculations.\
3.EmployeeRepository 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.
2.OPEN/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:
3.LISKOV 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!
4.Interface 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!
5.Dependency 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.