Interview Design Principles and Design Patterns
https://dotnettutorials.net/lesson/single-responsibility-principle/
What is the Single Responsibility Principle in C#?
The Single Responsibility Principle in C# states that “Each software module or class should have only one reason to change“. In other words, we can say that each module or class should have only one responsibility to do.
So we need to design the software in such a way that everything in a class or module should be related to a single responsibility. That does not mean your class should contain only one method or property, you can have multiple members (methods or properties) as long as they are related to a single responsibility or functionality. So, with the help of SRP in C#, the classes become smaller and cleaner and thus easier to maintain.
How can we achieve the Single Responsibility Principle in C#?
Let us understand the need for the Single Responsibility Principle in C# with an example. Suppose we need to design an Invoice class. As we know an Invoice class basically used to calculate various amounts based on its data. The Invoice class does not know how to retrieve the data, or how to format the data for display, print, logging, or sending an email, etc.
If we write the database logic, business logic as well as display logic in a single class, then our class performing multiple responsibilities. Then it becomes very difficult to change one responsibility without breaking the other responsibilities.
So, by mixing multiple responsibilities into a single class, we are getting the following disadvantage,
- Difficult to understand
- Difficult to test
- Chance of duplicating the logic of other parts of the application
Example: Without using Single Responsibility Principle in C#:
Please have a look at the following diagram that we want to implement in the following example.
-----------------------------
What is the Open-Closed Principle in C#?
The Open-Closed Principle states that “software entities such as modules, classes, functions, etc. should be open for extension, but closed for modification“.
Let us understand the above definition in simple words. Here we need to understand two things. The first thing is Open for extension and the second thing is Closed for modification. The Open for extension means we need to design the software modules/classes in such a way that the new responsibilities or functionalities should be added easily when new requirements come. On the other hand, Closed for modification means, we should not modify the class/module until we find some bugs.
The reason for this is, we have already developed a class/module and it has gone through the unit testing phase. So we should not have to change this as it affects the existing functionalities. In simple words, we can say that we should develop one module/class in such a way that it should allow its behavior to be extended without altering its source code.
Implementation Guidelines for the Open-Closed Principle (OCP) in C#
- The easiest way to implement the Open-Closed Principle in C# is to add the new functionalities by creating new derived classes which should be inherited from the original base class.
- Another way is to allow the client to access the original class with an abstract interface.
- So, at any given point of time when there is a change in requirement or any new requirement comes then instead of touching the existing functionality, it’s always better and suggested to create new derived classes and leave the original class implementation as it is.
Problems of Not following the Open-Closed Principle in C#:
If you are not following the Open-Closed Principle during the application development process, then you may end up your application development with the following problems
- If you allow a class or function to add new logic then as a developer you need to test the entire functionalities which include the old functionalities as well as new functionalities of the application.
- As a developer, it is also your responsibility to tell the QA (Quality Assurance) team about the changes in advance so that they can prepare themselves in advance for regression testing along with the new feature testing.
- If you are not following the Open-Closed Principle, then it also breaks the Single Responsibility Principle as the class or module is going to perform multiple responsibilities.
- If you are implementing all the functionalities in a single class, then the maintenance of the class becomes very difficult.
Because of the above key points, we need to follow the open-closed principle in C# while developing the application.
What is the Liskov Substitution Principle in C#?
The Liskov Substitution Principle is a Substitutability principle in object-oriented programming Language. This principle states that, if S is a subtype of T, then objects of type T should be replaced with the objects of type S.
In simple words we can say that, when we have a base class and child class relationships i.e. inheritance relationships, then, if we can successfully replace the object/instance of a parent class with an object/instance of the child class, without affecting the behavior of the base class instance, then it is said to be in Liskov Substitution Principle. If you are not getting this point properly, don’t worry, we will see some real-time examples to understand this concept.
For example, a father is a teacher whereas his son is a doctor. So here, in this case, the son can’t simply replace his father even though both belong to the same family.
Example: Without using the Liskov Substitution Principle in C#:
Let us first understand one example without using the Liskov Substitution Principle in C#. In the following example, first, we create the Apple class with the method GetColor. Then we create the Orange class which inherits the Apple class as well as overrides the GetColor method of the Apple class. The point is that an Orange cannot be replaced by an Apple, which results in printing the color of the apple as Orange as shown in the below example.
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";
}
}
---------------------------
What is the Dependency Inversion Principle in C#?
The Dependency Inversion Principle (DIP) states that high-level modules/classes should not depend on low-level modules/classes. Both should depend upon abstractions. Secondly, abstractions should not depend upon details. Details should depend upon abstractions.
The most important point that you need to remember while developing real-time applications, always to try to keep the High-level module and Low-level module as loosely coupled as possible.
When a class knows about the design and implementation of another class, it raises the risk that if we do any changes to one class will break the other class. So we must keep these high-level and low-level modules/classes loosely coupled as much as possible. To do that, we need to make both of them dependent on abstractions instead of knowing each other.
As per the Dependency Inversion Principle definition, “a high-level module should not depend on low-level modules. Both should depend on the abstraction”.
So, first, we need to figure out which one is the high-level module (class) and which one is the low-level module (class) in our example. A high-level module is a module that always depends on other modules. So, in our example, the EmployeeBusinessLogic class depends on EmployeeDataAccess class, so here the EmployeeBusinessLogic class is the high-level module and the EmployeeDataAccess class is the low-level module.
So, as per the first rule of the Dependency Inversion Principle in C#, the EmployeeBusinessLogic class/module should not depend on the concrete EmployeeDataAccess class/module, instead, both the classes should depend on abstraction.
The second rule of the Dependency Inversion Principle state that “Abstractions should not depend on details. Details should depend on abstractions”.
Before understanding this let us first understand what is an abstraction.
% important %
What is Abstraction?
In simple words, we can say that Abstraction means something which is non-concrete. So, abstraction in programming means we need to create either an interface or abstract class which is non-concrete so that we can not create an instance of it. In our example, the EmployeeBusinessLogic and EmployeeDataAccess are concrete classes that mean we can create objects of it.
As per the Dependency Inversion Principle in C#, the EmployeeBusinessLogic (high-level module) should not depend on the concrete EmployeeDataAccess (low-level module) class. Both classes should depend on abstractions, meaning both classes should depend on either an interface or an abstract class.
% important %
What should be in the interface (or in the abstract class)?
As you can see in the above example, the EmployeeBusinessLogic uses the GetEmployeeDetails() method of EmployeeDataAccess class. In real-time, there will be many employee-related methods in the EmployeeDataAccess class. So, we need to declare the GetEmployeeDetails(int id) method within the interface. Add one interface with the name IDataAccess and then copy and paste the following codes.
check code........................
Now, the EmployeeBusinessLogic and EmployeeDataAccess classes are loosely coupled classes because EmployeeBusinessLogic does not depend on concrete EmployeeDataAccess class, instead, it includes a reference of IEmployeeDataAccess interface. So now, we can easily use another class that implements IEmployeeDataAccess with a different implementation.
https://dotnettutorials.net/course/solid-design-principles/
What is the Open-Closed Principle in C#?
The Open-Closed Principle states that “software entities such as modules, classes, functions, etc. should be open for extension, but closed for modification“.
What is the Single Responsibility Principle in C#?
The Single Responsibility Principle in C# states that “Each software module or class should have only one reason to change“. In other words, we can say that each module or class should have only one responsibility to do
What is the Liskov Substitution Principle in C#?
The Liskov Substitution Principle is a Substitutability principle in object-oriented programming Language. This principle states that, if S is a subtype of T, then objects of type T should be replaced with the objects of type S.
What is the Interface Segregation Principle in C#?
The Interface Segregation Principle states that “Clients should not be forced to implement any methods they don’t use. Rather than one fat interface, numerous little interfaces are preferred based on groups of methods with each interface serving one submodule“.
What is the Dependency Inversion Principle in C#?
The Dependency Inversion Principle (DIP) states that high-level modules/classes should not depend on low-level modules/classes. Both should depend upon abstractions. Secondly, abstractions should not depend upon details. Details should depend upon abstractions.
SOLID Acronym
- S stands for the Single Responsibility Principle which is also known as SRP.
- O stands for the Open-Closed Principle which is also known as OSP.
- L stands for the Liskov Substitution Principle which is also known as LSP.
- I stand for the Interface Segregation Principle which is also known as ISP.
- D stands for Dependency Inversion Principle which is also known as DIP.
GIT SOURCE - https://github.com/vasanth32/Design_patterns_.Net/commits/main
Design Principles:
Design principles provide high level guidelines to design better software applications. They do not provide implementation guidelines and are not bound to any programming language. The SOLID (SRP, OCP, LSP, ISP, DIP) principles are one of the most popular sets of design principles.
For example, the Single Responsibility Principle (SRP) suggests that a class should have only one reason to change. This is a high-level statement which we can keep in mind while designing or creating classes for our application. SRP does not provide specific implementation steps but it's up to you how you implement SRP in your application.
Design principles are core abstract principles that we are supposed to follow while designing software. Remember they aren't concrete - rather abstract. They can be applied in any language, on any platform regardless of the state as long as we are within the permissible conditions.
Examples:
Encapsulate what varies.
Program to interfaces, not to implementations.
Depend upon abstractions. Do not depend upon concrete classes.
Design Patterns:
//
Design patterns are tested by others and are safe to follow, e.g. Gang of Four patterns: Abstract Factory, Factory, Singleton, Command, etc.
They are solutions to real-world problems that pop up time and again, so instead of reinventing the wheel, we follow the design patterns that are well-proven, tested by others, and safe to follow. Now, design patterns are specific; there are terms and conditions only in which a design pattern can be applied.
Examples:
Singleton Pattern ( One class can only have one instance at a time )
Adapter Pattern ( Match interface of different classes )
The following analogy will help you understand the difference better:
Principle: We should teach others in order to educate ourselves as well as others, and overall make our nation a progressive nation.
Pattern: In our country, each medical doctor graduate is supposed to teach 6 months in a far-away village to complete his/her degree.
Design Patterns .Net
SOLID
----------------
Comments
Post a Comment