SOLID principles allows object oriented programming implementation in an efficient better way into project development
S-->Single Responsibility Principle [SRP]
O-->Open Closed Principle [OCP]
L-->Liskov Substitution Principle [LSP]
I-->Interface Segregation Principle [ISP]
D-->Dependency Inversion Principle [DIP]
S-Single Responsibility Principle
This means that every class or similar structure in your code should have only one job.
The class should be provided with single responsibility related to a particular task.
A module or class should have a very small piece of responsibility in the entire application, This also reduces number of bugs and improves development speed and most importantly makes developer’s life lot easier
Example
It looks fine, but it is not following SRP.
The SendEmailTo and ValidateEmailAddres methods have nothing to do with the UserService class. Let's refract it.
Let's refract it to satisfy SRP
O: Open/Closed Principle
Software entities (classes, modules) should be opened for extension, but closed for modification.
This principle suggests that the class should be easily extended but there is no need to change its core implementations.
Now, the below code violates OCP principle if the bank introduces a new Account type. the code to be modified for adding a new account type.
We can apply OCP by using interface (or) abstract class when you want to extend functionality will create a new class to each type of acct type customer
Note:
when we need corporate acct type, we can create a new class by extending interface without modifying exiting class[no modification] but extension
In the above code three new classes are created; Regularsavingaccount, SalarySavingAccount, and CorporateAccount, by extending them from IAccount.
This solves the problem of modification of class and by extending interface, we can extend functionality.
Above code is implementing both OCP and SRP principle, as each class has single is doing a single task and we are not modifying class and only doing an extension.
In C#, Open/Closed principle can be applied using the following approaches:
Using Function Parameters
Using Extension methods
Using Classes, Abstract class, or Interface-based Inheritance
Generics
By using Interface
Now, some developers want to change the Method DebugDetails, So to satisfy there needs you need to modify the Logger class and either create a new method for them or modify the existing DebugDetails() method. If you change the existing DebugDetails() method then the other developers who don't want this change will also be affected.
To solve this problem is to use class based-inheritance (polymorphism)
Now, a new class can inherit the Logger class and change one or more method behavior
Liskov Substitution Principle[LSP]
Base classes must be able to use objects of derived classes without knowing it. LSP states that the child class should be perfectly substitutable for their parent class.
Base class var should be able to reference derived class object, it is called Upcasting principle
When you derived a class from a base class then the derived class should correctly implement all the methods of the base class. It should not remove some methods by throwing NotImplementedException.
LSP says that the derived class should correctly implement the base class methods.
To correct above implementation, we need to refactor this code by introducing interface with method called GetShape.
namespace Demo
{
class Program
{
static void Main(string[] args)
{
Shape shape = new Circle();
Console.WriteLine(shape.GetShape());
shape = new Triangle ();
Console.WriteLine(shape.GetShape());
}
}
public abstract class Shape
{
public abstract string GetShape();
}
public class Triangle: Shape
{
public override string GetShape()
{
return "Triangle";
}
}
public class Circle: Triangle
{
public override string GetShape()
{
return "Circle";
}
}
}
Output
Circle
Triangle
I-->Interface Segration Principle[ISP]
class should not be forced to implement methods which it does not need, and the contracts should be broken down to thin ones
[break one interface into different interfaces].
Using ISP, we can create separate interfaces for each operation or requirement rather than having a single interface with so many methods.
Example
We can resolve this violation by dividing IOrder Interface.
D-->Dependency Inversion Principle [DIP]
The Dependency Inversion Principle (DIP) states that high-level modules/classes should not depend on low-level modules/classes
Abstractions should not depend on details. Details should depend on abstractions.
The most important point you need to remember while developing real-time applications is always to keep the High-level and Low-level modules as loosely coupled as possible.
Refer Next Article of Mine to know more about Dependency Injection.