The SOLID principles are a set of design guidelines in object-oriented programming aimed at creating robust, maintainable, and scalable software. Coined by Robert C. Martin (Uncle Bob), these principles help developers avoid common pitfalls and write cleaner code.
S: Single Responsibility Principle (SRP)
Definition: A class should have only one reason to change.
Explanation: Each class should focus on a single responsibility or functionality. This makes code easier to understand, test, and maintain.
Example:
Instead of creating a User
class that handles data storage and email notifications, split it into User
for managing user data and EmailService
for handling email notifications.
public class UserService { public void AddUser(string name) { // Implement logic } } public class EmailService { public void SendEmail(string email) { // Implement logic } }
O: Open/Closed Principle (OCP)
Definition: Classes should be open for extension but closed for modification.
Explanation: Code should allow new functionality to be added without altering existing code. This promotes stability and reduces the risk of bugs.
Example:
Instead of modifying a class to add a new type of payment method, use interfaces or inheritance to extend functionality.
public interface IPayment { void Pay(); } public class CardPayment : IPayment { public void Pay() { // Card payment } } public class PaymentProcessor { public void Process(IPayment payment) { payment.Pay(); } }
L: Liskov Substitution Principle (LSP)
Definition: Subtypes must be substitutable for their base types without altering the correctness of the program.
Explanation: If a class B
is a subclass of class A
, then objects of type A
should be replaceable with objects of type B
without breaking the application.
Example:
If Rectangle
is a superclass and Square
inherits from it, ensure the subclass doesn’t alter behavior, such as how dimensions are set.
public interface IShape { int Area(); } public class Rectangle : IShape { public int Area() => Width * Height; } public class Square : IShape { public int Area() => Side * Side; }
I: Interface Segregation Principle (ISP)
Definition: A class should not be forced to implement interfaces it does not use.
Explanation: Split large interfaces into smaller, more specific ones. This ensures classes implement only what they need.
Example:
Instead of one large Animal
interface with methods like Fly()
, Swim()
, and Run()
, create specific interfaces like Flyable
, Swimmable
, and Runnable
.
public interface IFlyable { void Fly(); } public interface IWalkable { void Walk(); } public class Bird : IFlyable, IWalkable { public void Fly() { // Flying logic } public void Walk() { // Walking logic } }
D: Dependency Inversion Principle (DIP)
Definition: High-level modules should not depend on low-level modules; both should depend on abstractions.
Explanation: Rely on abstractions rather than concrete implementations to reduce coupling between components.
Example:
Instead of hardcoding a SQLDatabase
in a class, use an interface like IDatabase
, allowing easy switching to other databases (e.g., NoSQL).
public interface IDatabase { void Save(string data); } public class SQLDatabase : IDatabase { public void Save(string data) { // Save to SQL } } public class DataManager { public DataManager(IDatabase db) { db.Save("data"); } }
Why Use SOLID?
- Better Maintainability: Easier to understand and modify code.
- Scalability: Adapts well to new features or requirements.
- Reduced Bugs: Minimizes side effects when changes are made.
- Reusability: Code can be reused across projects.
Top comments (0)