Wednesday, 22 November 2017

SOLID PRINCIPLES

S.O.L.I.D. Principles:--
The term S.O.L.I.D. was introduced by Robert Cecil Martin, who is also know as Uncle Bob. S.O.L.I.D. is an acronym and stands for the 5 principles. Each of the letter in this is further having a 3 letter acronym, as per their names.
These principles are based on the concepts, which allows us to create structure of code which is very easy to extend, re-use, and make changes, which does not break the existing code. The names of these principles are based on the goals which these principles satisfy.
We will be discussing these principles one by one. So the term S.O.L.I.D. stands for :
S – Single Responsibility Principle : It says that There should never be more than one reason for a class to change.
O – Open/Closed Principle : It says that Classes should be open for extension, but closed for modification.
L – Liskov’s Substitution Principle : It says that Derived types must be completely substitutable for their base types.
I – Interface Segregation Principle : It says that Clients should not be forced to depend upon interfaces that they do not use.
D – Dependency Inversion Principle : It says that
High-level modules should not depend on low-level modules. Both should depend on abstractions.
Abstractions should not depend on details. Details should depend on abstractions.
S of S.O.L.I.D. or Single Responsibility Principle
This principle is first one of the 5 principles which are defined as an acronym S.O.L.I.D. This principle is further having an acronym called S.R.P. which is Single Responsibility Principle.
The general definition of this principle is
There should never be more than one reason for a class to change.
What this definition actually means is that each class should be given only one responsibility to handle, which is same as what the name of this principle implies. So let’s try to understand with an example. Consider the following code:
What this code is actually doing that it is saving the record in the database and sending the confirmation email to the users,
In future, a new requirement arrives that you need to save the data in another table in the SaveUser function, or add another parameter in the SendEmail function, or add any type of logging function in this class. So what you are required to do is, you have to perform more than one change in the same single class, and quite a good amount of chances are that the client code where this is used, will be affected by this change.
This is what is called the violation of the SRP or Single Responsibility principle.
So, to apply this principle, we have to separate the functions into separate classes, so that the email function becomes a common function (and can be used in different situations), and the SaveUser, can be independently used/modified.
So this is just an example of what is is the problem in the code and how we can apply this principle.
Two points that come to my mind from this principle are :
Using this principle does not means that we need to create a class for each and every function we need to perform (of-course practically this is not possible also)
O of S.O.L.I.D. or Open/Closed Principle
This is the second principle of the 5 principles which are defined as an acronym S.O.L.I.D. This principle is further having an acronym called O.C.P. which is Open/Closed Principle.
The general definition of this principle is
A Class should be Open for extension but closed for modification
So to start with, we have an application where we have two types of loggers. We use a method, which takes an input and uses the type of logger required to save the data of logs. So our code would look like the following :
This code will work fine. But we have a situation, where we are required to third type of logger. Then what happens ? We have to modify this existing class and add the third type of save method, and change the existing code.
This is what is called the violation of the SRP or Single Responsibility principle.
So, the best way to avoid these type of situations is to use abstraction using either abstract classes or interfaces, along with the Dependency Injection. So we introduce an interface ILogger, and make our logger classes implement this interface. Then, we use the dependency injection using constructor to decide which type is to be used. So our code will become :
So now our client code will be creating an instance of the Ilogger type based on the required type and calling the LogErrors method. So our client code will be :
Liskov Substitution Principle (LSP)
LSP states that the derived classes should be perfectly substitutable for their base classes.
If class D is derived from A then D should be substitutable for A.
Look at the following C# code sample where the LSP is broken. Simply, an Orange cannot substitute an Apple, which results in printing the color of apple as Orange.
namespace SolidDemo
{
class Program
{
static void Main(string[] args)
{
Apple apple = new Orange();
Console.WriteLine(apple.GetColor());
}
}
public class Apple
{
public virtual string GetColor()
{
return "Red";
}
}
public class Orange : Apple
{
public override string GetColor()
{
return "Orange";
}
}
}
Now let us re-factor and make it comply with LSP by having a generic base class for both Apple and Orange.
namespace SolidDemo
{
class Program
{
static void Main(string[] args)
{
Fruit fruit = new Orange();
Console.WriteLine(fruit.GetColor());
fruit = new Apple();
Console.WriteLine(fruit.GetColor());
}
}
public abstract class Fruit
{
public abstract string GetColor();
}
public class Apple : Fruit
{
public override string GetColor()
{
return "Red";
}
}
public class Orange : Apple
{
public override string GetColor()
{
return "Orange";
}
}
}
I of S.O.L.I.D. or Interface Segregation Principle
The general definition of this principle is
Client should not be forced to implement interfaces they don’t use.
So, this means, any class should be using or implementing only the interface which it needs, for its functionality.
Lets take a real world example. In an organization, each department is having its responsibility, like Development department will work on projects, HR team will be responsible for hiring new members, business development will be responsible for getting new projects for the company and so on. So if we talk about the code which will handle this, it could be something like the following :
Now, as we look into the code, we need to see is our HR team need to be concerned about getting projects for company or our business development team need to do the development etc. ? All the concrete classes are required to implement the functions, which are of no use of them(even if its empty).
This is the violation of Interface Segregation Principle.
This type of interface is also called as fat or polluted interface. So to avoid this, we break the responsibilities of each department into their individual tasks and define their own interfaces. So our code will become like the following:
So after creating separate interfaces, each department is concerned about its own department, and does not what other departments are up-to. Now, if you even add any new functionality to any interfaces, only the concerned department will be required to implement it.
One important thing to notice here is that, if you closely observe this principle, it seems quite similar to the Single responsibility principle.

D of S.O.L.I.D. or Dependency Inversion Principle
So this is the last of the 5 principles in the solid principles and is called Dependency Inversion principle. This principle is generally aimed at managing the coupling between two modules/classes with one of them dependent on the other and using it directly. This results in a very tightly coupled system. To avoid this type of situation, this principle is applied.
This principle has two points associated to it. These are
High level modules should not depend upon low level modules. Both should depend upon abstractions.
AND
Abstractions should not depend upon details. Details should depend upon abstractions.
I will come to the reason i am using this AND between these two statements after the discussion of the concept.
So before we start with the code, lets try to understand, what is the meaning of dependency in code, with a simple example. Consider the following snippet of code :
As you can see, here we have a logger class and a DbInteraction class. Here, our logger class acts as a low level class and the DbInteraction class acts as a high level complex class and this class is directly using the logger class in it. This is an example of a tightly coupled system.
This is the violation of the Dependency Inversion Principle, as high level class is directly dependent on the low level class. This can result in problem in future. If we have to add another type of logger, say log in the notepad or database, the complex class will be dependent on another concrete class, which further adds another reason to change the DbInteraction class. This is the violation of Single responsibility principle as well.
So. to avoid this kind of situation, we use the concept of Dependency Inversion principle. We will be implementing this principle in two steps :
Step 1 : Introduce the abstraction
To achieve this, we will be introducing the abstraction layer, which can be done either using the interface or abstract class, and will be having a simple method declaration to perform the logging operation. So our low level class i.e. the XMLLogger will be implementing this interface and our high level class will be using this interface based function to perform the logging operation. So our code becomes like the following :
So now it seems that the our code is fine, but still it is not. XMLLogger is getting instantiated inside the main class. So any new logger added, will again require us to make this class dependent on the newly added logger classes and they will have to be instantiated in this method itself. This again results in the violation of the Open/Closed & Single responsibility principles. So dependency is till there. Its time for Step 2.
Step 2 : Implement Dependency Injection
So, we will now introduce the dependency injection in this code, and the required object creation will be from the client code, and will be passed to this class using the constructor. This is what is called Constructor Dependency injection. So the dependency is injected into the high level class by the client code in following manner :
So here we get the advantage that whenever a new logger is to be added, we simply create it and implement the logger interface for it. Then finally, depending on the requirement, client code can instantiate the dependency in its code and pass it into the constructor of the DbInteraction class.
Now, at the start of this discussion, we used the AND statement between the two points which this principle refers to. The first principle is straight forward which says use the abstraction layers for interaction between to components. The second one might be a bit confusing, which says abstraction should not depend on details…
To be specific about this point, what this point actually means is that when we are introducing the abstraction, it should also not be depending on any concrete classes to satisfy the requirements of the derived classes, which is what we had at the start of our example, where we had no principle followed. For more details related to this point, you can check out the explanation at this link : http://programmers.stackexchange.com/....
S.O.L.I.D. principles vs Design patterns – Is S.O.L.I.D. same as the design patterns :--
No, these principles are not the same. They might sound quite close to these patterns especially the Structural patterns. But they are different. in their approach and their concept.
One important difference, which i have seen is that these principles focus more on the extension of the existing code classes rather than the modification, which is quite clear from the use of the Single responsibility and the Open/Closed principles . On the other hand, using the design patterns more or less will result in modification of the existing code and even sometimes you may find that design patterns may violate these principles, like, for example the use of the patterns like factory method or facade pattern. So more you study these concepts, more differences you will find.
Now the most important point of discussion is whether to go for learning these design patterns first or these principle. In my opinion, go for these principles first. This is because, i have been checking out the design patterns but suddenly i came to know about these principles. When i went through these principles, i found that these principles can act as the base of the design pattern, but not the other way around. You can extend your code much easily if you are using these principles, as compared to the use of design patterns. But this does not means that you should not go for the design patterns. You can improve your code writing drastically using these principles and patterns together and it will depend only on the situation that whether you can apply both at the same time or not.

No comments:

Post a Comment