SOLID Design Principles in ASP.NET with Examples

What are Design Principles?

Design Principles are high level guidelines or techniques to design better software programs. These are a set of rules, if applied in your program, can make your life a lot easier when there’s any enhancement or requirement change comes.

In normal language these principles are nothing but a way to design good software programs, which fixes a lot of design/architectural issues.

There are 5 Design principles we normally heard and use in our day today codding life and are called as the SOLID Principles.

S – Single Responsibility Principle
O – Open Closed Principle
L – Liskov Substitution Principle
I – Interface segregation Principle
D – Dependency Inversible Principle

Single Responsibility Principle

This principle says that a class must be responsible to do only one/single work, not more than that. So, the class must have only one reason for change.

Let’s say you have a class for Invoicing where you do all works related to invoicing like, calculating amount, taxes, shipping charges and all. Along with that you must do some other things as well like sending emails to customers and updating the Database.

So here the Single Responsibility Principle says that your invoicing class must not do anything apart from Invoicing like sending emails and updating Database. Hence keep those in separate classes and leave the Invoice class to focus only on Invoice part rather than focusing on multiple things.

Open Closed Principle

This principle says that entities like classes/methods/modules should be open for extension not modification. In simple words it states that once you developed and tested a method/class/module, you should only change it to fix bugs, but not to add new functionalities, rather you should have that scope for that classes/methods/modules to extend or adapt to have new functionalities.

Let’s say there is a class that is intended to do those invoicing works, which contains a lot of methods and properties to calculate and process invoice. We are done with the development and done with the unit testing and deployed it to production. Now some requirement changes happen where we have to introduce another type of invoice called recurring invoice.

Here our class should not be modified according to Open Closed Principle to add those functionalities because if we do that, all the testing we did will go in vain and we need to test it again. So here we should design the class in such a way that for any future requirements we should not change the class but extend it through interfaces or inheritance to adapt the requirement changes.

Liskov Substitution Principle

This principle says that the new derived classes should be perfectly substitutable for their bas classes. If class B is derived from class A then B should be replaceable with A.

Consider you have a class Fruit which has a derived class Apple, so wherever you use Fruit, there you should be able to use Apple as a substitutable.

Interface Segregation Principle

This principle states that clients should not be forced to implement those methods of an interface they do not want or use. So instead of having a single Interface break it down to multiple interfaces so that clients can only use those what they want to implement.

Consider a situation where we have a situation to design a solution for a Programmer, Lead and Manager. Where Programmer only do programming, Lead can program and manage and Manager can only manage.

So, in that case we should have two interfaces one for Programmer and one for Lead, so that the Programmer can implement only programmer class and Lead can implement both Lead class and programmer whereas Manager can implement only lead class.

Dependency Inversible Principle

This principle says two things;
  1. High level modules should not depend on low level modules, both should depend on abstraction.
  2. Abstraction should not depend on details but details should depend on abstraction.

When a class depends on another class, there is high chances that if we make some changes to one the other will be affected for sure. So, in this case we must keep the high level and low level logics loosely coupled as much as we can, for this we need to make both the classes dependent on abstraction instead knowing each other.

Example: Dependency injection is an example of this principle.

No comments:

Post a Comment