What is SOLID?
SOLID is an acronym for five design principles that make object-oriented software more understandable, flexible, and maintainable. These principles help developers create code that is easy to manage and extend. The five SOLID principles are:
- Single Responsibility Principle (SRP)
- Open/Closed Principle (OCP)
- Liskov Substitution Principle (LSP)
- Interface Segregation Principle (ISP)
- Dependency Inversion Principle (DIP)
1. Single Responsibility Principle (SRP)
The Single Responsibility Principle states that a class should have only one reason to change, meaning it should only have one job or responsibility.
Example in C#:
class Employee { public string Name { get; set; } public int Age { get; set; } // A method for calculating salary might belong in a separate class public double CalculateSalary() { // Logic for salary calculation } } class SalaryCalculator { public double CalculateSalary(Employee employee) { // Logic for salary calculation } }
By separating concerns, we follow SRP and ensure that changes in salary calculation don't affect the Employee class.
2. Open/Closed Principle (OCP)
The Open/Closed Principle states that a class should be open for extension but closed for modification. This means that you should be able to add new functionality without changing the existing code.
Example in C#:
public abstract class Shape { public abstract double Area(); } public class Circle : Shape { public double Radius { get; set; } public override double Area() => Math.PI * Radius * Radius; } public class Rectangle : Shape { public double Width { get; set; } public double Height { get; set; } public override double Area() => Width * Height; }
By using polymorphism, you can add new shapes without modifying the existing code, adhering to the OCP.
3. Liskov Substitution Principle (LSP)
The Liskov Substitution Principle states that objects of a base class should be replaceable with objects of derived classes without affecting the correctness of the program.
Example in C#:
public class Bird { public virtual void Fly() { } } public class Sparrow : Bird { public override void Fly() { // Sparrow flies } } public class Penguin : Bird { public override void Fly() { // Penguins can't fly, violates LSP } }
In this example, the Penguin class violates LSP because a Penguin cannot fly. To follow LSP, you might have a separate interface for birds that can fly.
4. Interface Segregation Principle (ISP)
The Interface Segregation Principle states that clients should not be forced to implement interfaces they do not use.
Example in C#:
public interface IWorkable { void Work(); } public interface IScalable { void Scale(); } public class Worker : IWorkable, IScalable { public void Work() { } public void Scale() { } } public class Manager : IWorkable { public void Work() { } }
By using smaller, specific interfaces, classes only need to implement what is relevant to them, adhering to ISP.
5. Dependency Inversion Principle (DIP)
The Dependency Inversion Principle states that high-level modules should not depend on low-level modules. Both should depend on abstractions. Furthermore, abstractions should not depend on details. Details should depend on abstractions.
Example in C#:
public interface IReader { string Read(); } public class FileReader : IReader { public string Read() { return "Reading from file"; } } public class DataProcessor { private readonly IReader _reader; public DataProcessor(IReader reader) { _reader = reader; } public void Process() { string data = _reader.Read(); // Process the data } }
In this example, DataProcessor depends on the abstraction (IReader), not on the concrete class (FileReader), following DIP.
Conclusion
By adhering to the SOLID principles, C# developers can create more maintainable, scalable, and flexible applications. These principles lead to better software design, making code easier to understand and extend while minimizing the risk of bugs.