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)