Skip to content

Solid Principles Full Tutorial In C Interview Answers Design Patterns In NET Coding Examples

FurkanGozukara edited this page Oct 27, 2025 · 1 revision

Solid Principles Full Tutorial In C# - Interview Answers - Design Patterns In .NET - Coding Examples

Solid Principles Full Tutorial In C# - Interview Answers - Design Patterns In .NET - Coding Examples

image Hits Patreon BuyMeACoffee Furkan Gözükara Medium Codio Furkan Gözükara Medium

YouTube Channel Furkan Gözükara LinkedIn Udemy Twitter Follow Furkan Gözükara

In this lecture video I am explaining what are solid design principles. I am composing a .NET Core 7 WPF project to demonstrate each one of the principles of the solid design in C-Sharp programming language. I believe that the best methodology for learning something is doing an actual programming example. Therefore, we will make examples together.

SOLID is acronym of:

S - SRP - Single responsibility principle

O - OCP - Open/closed principle

L - LSP - Liskov substitution principle

I - ISP - Interface segregation principle

D - DIP - Dependency inversion principle

Foreach principle, I am composing 2 classes that shows violation and correct approach.

The source code of the lecture is available on : 🔗 https://github.com/FurkanGozukara/Solid-Principles-Full-Tutorial-In-C-Interview-Answers-Design-Patterns-In-.NET-Coding-Examples

The subtitles of the video is manually corrected so please watch with subtitles.

Please join Our Discord server for asking questions and have discussions: 🔗 https://discord.gg/rfttctFewW

Please follow us on Twitter: 🔗 https://twitter.com/SECourses

Please follow us on Facebook: 🔗 https://www.facebook.com/OfficialSECourses

If you are interested in programming our playlists will teach you how to program and code from scratch: 🔗 https://www.youtube.com/c/SECourses/playlists

[1] Introduction to Programming Full Course with C# playlist

[2] Advanced Programming with C# Full Course Playlist

[3] Object Oriented Programming Full Course with C# playlist

[4] Asp #NETCore V5 - MVC Pattern - Bootstrap V5 - Responsive Web Programming with C# Full Course Playlist

[5] Artificial Intelligence (AI) and Machine Learning (ML) Full Course with C# Examples playlist

[6] Software Engineering Full Course playlist

[7] Security of Information Systems Full Course playlist

Video Transcription

  • 00:00:00 Hello everyone. I am Dr. Furkan Gözükara.  Today I am going to explain to you what are  

  • 00:00:06 solid design principles. I will compose a .NET  Core 7 WPF project to demonstrate each one of  

  • 00:00:12 the principles of the solid design in C-Sharp  programming language. I believe that the best  

  • 00:00:18 methodology for learning something is doing an  actual programming example. The code written  

  • 00:00:22 in this lecture will be uploaded to our public  GitHub repository so that you can download and  

  • 00:00:27 use it yourself. I will put the link of the  repository in the description of the video.  

  • 00:00:33 So let's start with composing our WPF project.  You see I have clicked create a new project in  

  • 00:00:40 Visual Studio Community Edition and  I have filtered the result with WPF.  

  • 00:00:46 There are two versions of WPF. The first one  is WPF application which is .NET Core and  

  • 00:00:53 there is also another version which is WPF of .NET  Framework. .NET Framework is the older one and it  

  • 00:00:59 is not updated anymore. So be careful with that.  I am picking the WPF application with .NET Core  

  • 00:01:09 and let's pick our folder name  as solid design principles.  

  • 00:01:19 I will pick the .NET 7 standard term support.  Okay, so our application is starting. So  

  • 00:01:26 let's quickly review and understand what are the  solid design principles and why do we need them.  

  • 00:01:37 Okay. Why do we need solid design principles?  As a developer, we start developing applications  

  • 00:01:46 using our experience and knowledge. But over  time, the applications might arise bugs.  

  • 00:01:53 We need to alter the application design for every  change request or for a new feature request.  

  • 00:01:59 After some time we might need to put a lot of  effort, even for simple tasks, it might require  

  • 00:02:04 the full working knowledge of the entire system.  But we can't blame change or new feature requests  

  • 00:02:11 as they are part of the software development.  We can't stop them and refuse them either.  

  • 00:02:17 So who is the culprit here? Obviously,  it is the design of the application.  

  • 00:02:23 Okay, this is so true. I have 13 years of software  development experience and I assure you that you  

  • 00:02:30 will have to fix and improve so many parts of  your application after its initial release.  

  • 00:02:39 You will encounter bugs and you will  and you will get a new feature request.  

  • 00:02:44 So if you design your application with following  the state of art principles, then you will have  

  • 00:02:55 less problems. Okay, this is why solid design  principles is really important in application  

  • 00:03:03 development. So let's continue reading.  Advantages of solid design principles in C#.  

  • 00:03:12 As a developer, while you are designing  and developing any software applications,  

  • 00:03:17 then you need to consider the following  points. Maintainability. Nowadays,  

  • 00:03:23 maintaining the software is the biggest challenge  for the industry. Day by day, the business grows  

  • 00:03:29 for the organization and as the business grows,  you need to enhance the software with new changes.  

  • 00:03:35 So you need to design the software in such a way  that it should accept future changes with minimum  

  • 00:03:40 effort and without any problem. Okay, I am pretty  sure that you have already noticed this in the  

  • 00:03:48 applications that you use in your real life. You  see that your applications always gets new updates  

  • 00:03:55 and gets new features. So this is something that  you can't avoid in your software development life.  

  • 00:04:07 Testability. Test-driven development TDD  is one of the most important key aspects  

  • 00:04:14 nowadays when you need to design and develop a  large-scale application. We need to design the  

  • 00:04:20 application in such a way that we should test  each individual functionalities. Okay, this is  

  • 00:04:25 another thing in the nowadays programming trends  that your code has to be automatically testable.  

  • 00:04:35 This is also mandatory in continuous  development and continuous integration scheme  

  • 00:04:42 following application development. Okay.  

  • 00:04:50 Flexibility and Extensibility.  

  • 00:04:54 Nowadays, flexibility and extensibility both are  very much required for enterprise applications.  

  • 00:05:01 So we should design the application in such  a way that it should be flexible so that it  

  • 00:05:05 can be adapted to work in different ways and  extensible so that we can add new features  

  • 00:05:10 easily with minimum modifications. Okay,  this is also another important thing and  

  • 00:05:15 when we follow correct design principles,  we won't have a hard time to achieve this.  

  • 00:05:24 Parallel Development. The parallel development  of an application is one of the most important  

  • 00:05:31 key aspects. As we know, it is not possible  to have the entire development team will work  

  • 00:05:36 on the same module at the same time. So  we need to design the software in such a  

  • 00:05:42 way that different teams can work on different  modules. The solid design principles and design  

  • 00:05:48 patterns play an important role in achieving  all of the above key points. All right.  

  • 00:05:58 The solid design principles in C# are the design  principles that basically used to manage most of  

  • 00:06:04 the software design problems that generally  we encountered in our day-to-day programming.  

  • 00:06:09 These design principles are provided with some  mechanism that will make the software designs  

  • 00:06:14 more understandable, flexible and maintainable.  What is the main reason behind most of the  

  • 00:06:21 unsuccessful applications? The following are the  main reasons for most of the software failures.  

  • 00:06:28 Putting more functionalities on classes. In  the simple word a lot of functionalities we  

  • 00:06:34 are putting into the class even though  they are not related to the class.  

  • 00:06:39 Implementing tight coupling between the classes.  If the classes are dependent on each other,  

  • 00:06:45 then a change in one class will  affect the other classes also.  

  • 00:06:49 How to overcome the unsuccessful application  development problem? We need to use the correct  

  • 00:06:56 architecture, (i.e. MVC, Layered, 3-tier, MVP,  and so on) as per the project requirements.  

  • 00:07:05 As a developer, we need to follow the  design principles, i.e. solid principles.  

  • 00:07:11 Again, we need to choose the correct design  patterns as per the project requirements.  

  • 00:07:17 Introduction to solid design principles in  C-sharp. The solid design principles are  

  • 00:07:24 basically used to manage most of the software  design problems that generally as a developer  

  • 00:07:28 we face in our day-to-day programming. Solid  principles represent five design principles  

  • 00:07:34 that basically used to make the software designs  more understandable, flexible, and maintainable.  

  • 00:07:41 Solid acronym: Okay, this is important.  Usually, nowadays, in the job interviews,  

  • 00:07:48 they are asking you what does solid mean. They  are asking you to explain each one of these  

  • 00:07:55 design principles. I have been asked actually.  And so let's try to memorize and understand them.  

  • 00:08:05 S stands for the single responsibility  principle, which is also known as SRP. Okay,  

  • 00:08:10 don't worry that I will explain each  one of these principles with details.  

  • 00:08:18 O stands for the open-closed  principle, which is also known as OSP.  

  • 00:08:24 L stands for the Liskov substitution  principle, which is also known as LSP.  

  • 00:08:30 I stand for the interface segregation  principle, which is also known as ISP.  

  • 00:08:36 D stands for dependency inversion  principle, which is also known as DIP.  

  • 00:08:42 What are the advantages of using  solid design principles in C-sharp?  

  • 00:08:47 We will get the following advantages of using  solid design principles in C-sharp. Achieve the  

  • 00:08:54 reduction in complexity of the code. Increase  readability, extensibility, and maintenance.  

  • 00:09:02 Reduce error and implement reusability. Achieve  better testability. Reduce tight coupling. Okay,  

  • 00:09:11 so actually we can say that each one of  these is matching these ones. The first  

  • 00:09:18 one achieves reduction in complexity of the  code with single responsibility, because each  

  • 00:09:23 class is responsible for only one thing. Okay,  one job, and it reduces complexity. You see,  

  • 00:09:31 open-closed principle increases readability,  extensibility, and maintenance, because our  

  • 00:09:39 code will be closed to modify, but it will be  open to extend, and with Liskov substitution  

  • 00:09:49 principle, we will reduce error and implement  reusability. It will allow us to reuse our code  

  • 00:09:55 as much as possible with easiness, and with  interface segregation principle, we will achieve  

  • 00:10:01 better testability, and with dependency inversion  principle, we will reduce tight coupling. Okay,  

  • 00:10:09 so let's start programming with  single responsibility principle.  

  • 00:10:15 Okay, so let's quickly read what does  it do, what is the meaning of it.  

  • 00:10:24 What is the single responsibility principle  in C#? The single responsibility principle  

  • 00:10:31 in C# states that each software module or  class should have only one reason to change.  

  • 00:10:37 In other words, we can say that each module or  class should have only one responsibility to do.  

  • 00:10:44 So we need to design the software in such a way  that everything in a class or module should be  

  • 00:10:49 related to a single responsibility. That does not  mean your class should contain only one method or  

  • 00:10:56 property, you can have multiple members, methods,  or properties, as long as they are related to a  

  • 00:11:01 single responsibility or functionality. So with  the help of SRP in C-sharp, the classes become  

  • 00:11:09 smaller and cleaner and thus easier to maintain.  Okay, so you see why it is becoming easier to  

  • 00:11:15 maintain. So let's start with coding. The first  example is the opposite of single responsibility.  

  • 00:11:22 Assume that we have invoice class. Let's  start implementing it. All right. Okay,  

  • 00:11:32 so the first example will be an example that  violates single responsibility principle.  

  • 00:11:48 Okay. By the way, I have written  this correctly, I think. Okay, let's  

  • 00:11:58 make it like this. Okay, example that  violates single responsibility. Okay.  

  • 00:12:13 All right. So let's add a class. I'm going  to add single responsibility violation class.  

  • 00:12:31 And I will copy-paste the code here. All right.  

  • 00:12:42 Okay, so what do we have? Let's analyze  it. We have a class invoice. It has a  

  • 00:12:51 long invoice amount. We have daytime invoice  date. They are, as you can see, attributes.  

  • 00:13:03 Okay, and we have add invoice method. You see  it in add invoice method. We are also sending  

  • 00:13:11 an email. Okay. And if if an error happens,  we are also logging the error. So this method  

  • 00:13:19 actually doing three separate things. With direct  implementation, we have delete invoice method.  

  • 00:13:38 Which also logs, as you can see here, and  we have send invoice email. All right.  

  • 00:13:51 And okay. Okay, so with this way, we are violating  our principle. Why? Because we are doing three  

  • 00:14:07 separate things in a single class like this. Okay,  let me show single responsibility violation. Okay.  

  • 00:14:17 And  

  • 00:14:25 here we are just calling. Okay, these are  not public or. Okay. We need to generate.  

  • 00:14:44 One second. Okay, we don't need actually this.  

  • 00:14:53 Like this. Violated invoice or  let's say incorrect invoice.  

  • 00:15:06 And incorrect invoice. Add invoice. Okay, like  this. So this usage is not the correct way. Okay.  

  • 00:15:16 How then if it is incorrect, then how can we fix  this? To fix this, we need to separate the tasks  

  • 00:15:26 that each the task here inside here into different  classes. Okay, so first let's start adding with  

  • 00:15:38 a logger system. That login logger class will  handle the logging if an error happens. Okay.  

  • 00:15:46 So to adding the logger system, I will  just copy and paste this. You see,  

  • 00:15:52 all of these can be inside the parent class,  but they will have different subclasses names.  

  • 00:15:59 So we are separating the concern. I mean, they  can be inside this same CS file. Or you could  

  • 00:16:06 also do you could also insert different  CS files as well. Maybe we should add  

  • 00:16:15 different CS files so it will be easier to  manage. So let's add a logger CS file. Okay,  

  • 00:16:25 in parent class logger, so I will just change it.  

  • 00:16:33 Like this. Okay, so we have an interface and with  interface we define which methods this inheriting  

  • 00:16:43 class or yes, inheriting class should have. So we  have a logger class that uses interface iLogger  

  • 00:16:51 and inside we are constructing the methods.  We have constructor, we have info method,  

  • 00:16:58 we have debug method and we have error method. You  can fill anything inside here. The purpose of this  

  • 00:17:05 lecture to demonstrate how to do proper solid  design principles following programming. So we  

  • 00:17:14 also need to now modify our code. Oh, we also need  to add another class for mail messaging. Okay.  

  • 00:17:26 So let's add a mail sender class.  

  • 00:17:34 All right, let's name it as mail  sender. And inside here, make it as  

  • 00:17:44 public class mail sender. You see mail sender  has only one purpose and it is send email.  

  • 00:17:50 All right. Okay, now finally we can modify our  invoice class properly to be following solid  

  • 00:18:00 design principles. And for that, okay, let's  add another button. You know, you can fill  

  • 00:18:09 anything inside these methods. Okay, and let's  call it as proper single responsibility. Okay.  

  • 00:18:30 All right, so I am going to add another  class and I will say proper invoice.  

  • 00:18:37 Okay, let's name it as proper invoice.  

  • 00:18:43 Okay, we can leave it as internal as well  for the demo and let's copy and paste code.  

  • 00:18:52 Okay, so I also need to change the constructor  name. All right. So what is the difference in  

  • 00:19:03 this case? In this case, you see, we have a logger  and mail sender as injection dependency injection.  

  • 00:19:17 Actually, not this. Okay. And then  we use those initialized objects  

  • 00:19:25 to add info or send email. Okay, you  see, if an error occurs, then we are  

  • 00:19:37 using the error method like here. All  right. And why does it show error?  

  • 00:19:47 Okay, because I need to send it like this. And  in the other case, we also modify it like this.  

  • 00:19:57 You see, instead of sending email  directly inside in the first case.  

  • 00:20:03 In the violation method. In the violation method  methodology, we were sending mail directly like  

  • 00:20:11 this. The code was also written in the same  class and we were also logging the errors like  

  • 00:20:17 this. However, now we have separate classes for  each task. We have mail sender class and we have  

  • 00:20:25 file logger. Okay. And now we can use each one of  them. So if we change anything in these separate  

  • 00:20:36 classes that it won't affect anything in our  application workflow runtime. This is a single  

  • 00:20:48 responsibility principle. And let's see if  the author of this article said anything.  

  • 00:20:58 Okay. As you can see, the invoice class delegating  the logging activity to the logger class.  

  • 00:21:07 In the same way, delegate the email  sending activity to the mail sender class.  

  • 00:21:13 Now the invoice class now only  concentrates on invoice related activities.  

  • 00:21:18 All right, now we can move to the next  principle, which is open-closed principle.  

  • 00:21:30 What is the open-closed principle in C-sharp?  

  • 00:21:35 The open-closed principle states that software  entities such as modules, classes, functions,  

  • 00:21:41 etc. should be open for extension,  but closed for modification.  

  • 00:21:46 Let us understand the above definition in simple  words. Here we need to understand two things.  

  • 00:21:53 The first thing is open for extension and  the second thing is closed for modification.  

  • 00:21:59 The open for extension means we need to design  the software modules / classes in such a way  

  • 00:22:05 that the new responsibilities or functionalities  should be added easily when new requirements come.  

  • 00:22:11 On the other hand, closed for modification means  we should not modify the class / module until we  

  • 00:22:17 find some bugs. The reason for this is we have  already developed a class / module and it has  

  • 00:22:24 gone through the unit testing phase. So we  should not have to change this as it affects  

  • 00:22:29 the existing functionalities. In simple words, we  can say that we should develop one module / class  

  • 00:22:36 in such a way that it should allow its behavior  to be extended without altering its source code.  

  • 00:22:46 Implementation guidelines for the open-closed  principle, OCP, in C-sharp. The easiest way  

  • 00:22:54 to implement the open-closed principle in  C-sharp is to add the new functionalities  

  • 00:22:59 by creating new derived classes which should  be inherited from the original base class.  

  • 00:23:05 Another way is to allow the client to access  the original class with an abstract interface.  

  • 00:23:13 So, at any given point of time when there is  a change in requirement or any new requirement  

  • 00:23:18 comes then instead of touching the existing  functionality, it's always better and suggested  

  • 00:23:22 to create new derived classes and leave the  original class implementation as it is. Okay,  

  • 00:23:28 so this is the key issue, the key point. Whenever  you need a new functionality, then you shouldn't  

  • 00:23:36 change the existing implementation. You should  extend it and then implement that new feature with  

  • 00:23:45 that extension. Okay, this is really important,  the key part of the open-closed principle.  

  • 00:23:53 By the way, in an interview I was asked what is  open-closed principle and I was asked to explain  

  • 00:24:00 it, so this is really important. Problems of not  following the open-closed principle in C-sharp.  

  • 00:24:08 If you are not following the open-closed principle  during the application development process,  

  • 00:24:13 then you may end up your application development  with the following problems. If you allow a class  

  • 00:24:20 or function to add new logic then as a developer  you need to test the entire functionalities which  

  • 00:24:25 include the old functionalities as well  as new functionalities of the application.  

  • 00:24:31 As a developer, it is also your responsibility  to tell the QA, quality assurance, team about  

  • 00:24:37 the changes in advance so that they can prepare  themselves in advance for regression testing  

  • 00:24:41 along with the new feature testing. If you  are not following the open-closed principle,  

  • 00:24:47 then it also breaks the single responsibility  principle as the class or module is going to  

  • 00:24:52 perform multiple responsibilities. If you  are implementing all the functionalities in  

  • 00:24:58 a single class, then the maintenance  of the class becomes very difficult.  

  • 00:25:06 Because of the above key points, we need to  follow the open-closed principle in C-sharp  

  • 00:25:12 while developing the application.  Okay, so let's start coding it.  

  • 00:25:18 The first example will be an example that  

  • 00:25:23 breaks the open-closed principle. Let's name it  as example breaks open-closed principle. Alright,  

  • 00:25:49 let's copy and paste the code.  

  • 00:26:12 So I'm going to add another  class breaks open-closed.  

  • 00:26:25 Okay, so let's check it out. And what  does that mean? We have invoice class  

  • 00:26:32 and that invoice class has get invoice  discount, which takes two parameters,  

  • 00:26:38 which is amount and the invoice type.  So according to the invoice type,  

  • 00:26:43 we are returning the discount amount. And  what is wrong here? You see that this method  

  • 00:26:56 is doing different tasks based on the invoice  type. Okay, so if I want to add another invoice  

  • 00:27:06 type here, let's say extra invoice, then what do I  need to do for implementation? For implementation,  

  • 00:27:14 then I need to add more else if like this.  And you see as I add more invoice types,  

  • 00:27:24 then I need to modify this existing class  further. And this totally breaks open-closed  

  • 00:27:33 principle because I am modifying the existing  class method for extending its functionality.  

  • 00:27:41 Okay, and this breaks the open-closed  principle. And as explained in the article,  

  • 00:27:50 this forces us to retest all of the functionality  and report to the quality assurance team and  

  • 00:27:59 other things. So I need to modify this  in a way that it won't break it anymore.  

  • 00:28:06 Let's make example of this  in our application. Okay,  

  • 00:28:30 now let's fix it in a way that it won't break our  functionality. I mean the open-closed principle.  

  • 00:28:41 Okay, let's say proper open-closed principle.  

  • 00:29:05 So what do we need to do is we need to generate a  base class and extend it. In this case, it will be  

  • 00:29:12 like this. Let's copy paste and analyze it. Let's  add another class and name as proper open-closed.  

  • 00:29:25 Okay, so now we have a base class as invoice and  this invoice class has a virtual method. Virtual  

  • 00:29:36 methods can be overridden by the inheriting  classes and it has a get invoice discount  

  • 00:29:47 and double amount. Okay, and it's just deducts 10  point from the amount and return it. Then we have  

  • 00:29:57 final invoice, which has a get invoice discount  method and it overrides the base method with  

  • 00:30:05 double amount. Then it gets the base. It calls  the base get invoice and minus 50. This is the  

  • 00:30:14 final invoice. You see, these are the actual  invoice types that we have in. Let me show again.  

  • 00:30:23 Okay, here we had final invoice,  which was deducting 100 percent.  

  • 00:30:30 And we had proposed it, which was deducting 50 and  we had extra invoice, which was deducting 75. So  

  • 00:30:38 for final invoice, we need to deduct 90 actually  to make it equal and for proper proposed invoice,  

  • 00:30:47 it is minus 50. Yeah, this is correct. And  okay, by the way, when we provide amount. Okay.  

  • 00:30:57 Yes, it's true. And there is a recurring  invoice. Okay, let's fix this in this case.  

  • 00:31:18 Yeah, now fix it. It is minus 30. Let's make  it minus 65. Okay. So you see, this is how  

  • 00:31:28 we are extending the functionality of the class  with inheritance. Okay. I can add so many other  

  • 00:31:39 new invoice types here like super invoice.  Okay. And I can say that just minus five.  

  • 00:31:49 Okay. So it is totally up to you to extend it.  Now it looks much better. It is easier to read.  

  • 00:31:55 It is easier to manage and it won't break our  existing code. It won't require retesting and  

  • 00:32:04 validating our existing code because it is just  extending the base class. Okay. And let's make  

  • 00:32:13 an example call of that. By the way, this is not  valid anymore. Yeah. In this case, proper. Okay.  

  • 00:32:28 So you see, now I can define each one of them.  Let's say recurring invoice, recurring invoice.  

  • 00:32:40 And then just I can say get invoice  discount with something like this. Okay.  

  • 00:32:49 All right. And yeah, they all  made an example such that they.  

  • 00:32:59 Now the invoice class is closed for modification,  

  • 00:33:03 but it is open for the extension as it allows  creating new classes deriving from the invoice  

  • 00:33:08 class, which clearly follows the open closed  principle in C sharp. In the next article. Okay.  

  • 00:33:15 So let's move to Liskov substitution principle and  let's just read its definition. All right. Okay.  

  • 00:33:27 What is the Liskov substitution principle in  C sharp? The Liskov substitution principle is  

  • 00:33:35 a substitutability principle in object oriented  programming language. This principle states that  

  • 00:33:41 if S is a subtype of T, then objects of type T  should be replaced with the objects of type S.  

  • 00:33:49 In simple words we can say that, when we have a  base class and child class relationships i.e.,  

  • 00:33:55 inheritance relationships, then, if we can  successfully replace the object / instance  

  • 00:34:00 of a parent class with an object / instance  of the child class, without affecting the  

  • 00:34:05 behavior of the base class instance, then it  is said to be in Liskov substitution principle.  

  • 00:34:11 If you are not getting this point properly, don't  worry, we will see some real time examples to  

  • 00:34:16 understand this concept. For example, a father is  a teacher whereas his son is a doctor. So here,  

  • 00:34:25 in this case, the son can't simply replace his  father even though both belong to the same family.  

  • 00:34:31 Okay, so let's make an example. First, we will  make an example that violates Liskov's principle.  

  • 00:34:58 Alright, so to demonstrate a violation of  Liskov's principle, I will just add a class here.  

  • 00:35:20 Okay, and we have two classes. The first class is  apple and the second class is orange. You know,  

  • 00:35:28 apples and oranges are totally different  things. So, we shouldn't be able to define apple  

  • 00:35:40 as an orange and get its color. Okay, this is  a violation. Let's see what does that mean.  

  • 00:35:52 Okay, so let's define first, okay,  Liskov violation, apple dot, okay, apple,  

  • 00:36:03 and let's see, MessageBox.Show apple, and let's  say, apple color. One second, sorry about that.  

  • 00:36:23 And let's define orange. Okay, this will  be an orange. Let's say orange color.  

  • 00:36:44 And now I am going to define  

  • 00:36:48 an apple from orange type. Okay, what does  that mean? It means that something like this.  

  • 00:36:56 Let's say apple, and let's get its color. Okay,  apple orange color. Okay, orange type apple color.  

  • 00:37:15 So, what we want in this case is to get the  type of, get the color of orange, not the,  

  • 00:37:23 I mean to get the type of apple, not the orange.  Because this is apple type and orange can't  

  • 00:37:30 replace it. However, in this case, we are going  to get the color of orange instead of apple. Okay,  

  • 00:37:38 so let's run our application to verify. We have  apple color red, we have orange color red, and  

  • 00:37:46 we have orange type color orange. Why do we have  an error here? Let's fix it. Okay, now it will be,  

  • 00:37:55 okay, apple color red, orange color orange,  and we have orange type apple color orange. And  

  • 00:38:02 this is the violation of Liskov principle. Why?  Because, as you can see in the above example,  

  • 00:38:11 apple is the base class and orange is the child  class i.e. there is a parent-child relationship.  

  • 00:38:18 So, we can store the child class object in  the parent reference variable i.e. apple  

  • 00:38:23 apple equals new orange, and when we call  the get color i.e. apple dot get color,  

  • 00:38:28 then we are getting the color of the orange  not the color of apple. That means once the  

  • 00:38:33 child object is replaced i.e. apple storing the  orange object, the behavior is also changed. Okay,  

  • 00:38:40 this is the key issue. The behavior is changed  and this is violation of Liskov substitution  

  • 00:38:49 principle. This is against the LSP principle. The  Liskov substitution principle in C sharp states  

  • 00:38:57 that even the child object is replaced with the  parent, the behavior should not be changed. So,  

  • 00:39:03 in this case, if we are getting the color of apple  instead of orange, then it follows the Liskov  

  • 00:39:09 substitution principle. So if we were seeing  the color of apple then it would be following  

  • 00:39:14 the Liskov substitution principle. That means  there is some issue with our software design.  

  • 00:39:21 Let us see how to overcome the design  issue and makes the application follow  

  • 00:39:25 Liskov substitution principle. Okay,  so let us make the proper example.  

  • 00:39:39 Okay, I will name it as Liskov.  

  • 00:39:55 All right, and let's add a new class as here  proper Liskov. And let's copy and paste the code.  

  • 00:40:32 Okay, so let's check out the difference. So now  we have an abstract class which is fruit. So in  

  • 00:40:40 this abstract class, we have get color method  and it is also abstract as you can see. So any  

  • 00:40:48 class that inherits this abstract class has to  define this method. So we have apple which has  

  • 00:40:56 red and it is overriding the abstract class in the  fruit abstract class abstract method in the in the  

  • 00:41:06 abstract class of fruit and we have orange. You  see, we didn't override the base class method. We  

  • 00:41:14 overrided the abstract class method different than  the first example. And now let's make our test  

  • 00:41:26 in the same way. So this time it  will be proper Liskov principle.  

  • 00:41:39 Okay, and you see now I am not able to define  

  • 00:41:44 apple with the type of orange. Okay,  so let's call this as fruit orange.  

  • 00:41:53 And it will be fruit orange and  you see how it makes sense now.  

  • 00:42:01 Okay, fruit orange and fruit apple. Okay, yes, and  now it is much more sense making and it will work  

  • 00:42:16 correctly. Okay, apple color red, orange color  orange, fruit orange color orange and fruit  

  • 00:42:23 apple color red. As expected, working perfectly  fine and it's now follows the Liskov principle.  

  • 00:42:33 Okay, now time to see interface  segregation principle.  

  • 00:42:45 What is the interface segregation principle in C  sharp? The interface segregation principle states  

  • 00:42:52 that clients should not be forced to implement  any methods they don't use. Rather than one fat  

  • 00:42:58 interface, numerous little interfaces are  preferred based on groups of methods with  

  • 00:43:03 each interface serving one sub module. Let us  break down the above definition into two parts.  

  • 00:43:11 First, no class should be forced to implement  any methods of an interface they don't use.  

  • 00:43:18 Secondly, instead of creating large or you can say  fat interfaces, create multiple smaller interfaces  

  • 00:43:24 with the aim that the clients should only think  about the methods that are of interest to them.  

  • 00:43:29 Sorry about that, it was  my baby child, my daughter.  

  • 00:43:37 Okay, as per the single responsibility principle  of solid like classes, interfaces also should have  

  • 00:43:45 a single responsibility. That means we shouldn't  force any class to implement any methods which  

  • 00:43:51 they don't require. Okay, so you see how these  principles are, let's say, tightly coupled. So  

  • 00:43:59 one principle requires another principle and when  you follow all of them, they are working like as  

  • 00:44:06 a team. Okay, so let's start with a violation  of interface segregation principle. All right.  

  • 00:44:21 Okay, let's call it as violation  of interface segregation.  

  • 00:44:42 All right. And let's copy and paste our class. So  let's add a new class first. Interface violation.  

  • 00:45:03 And here, first, we have public interface, I  printer tasks. Okay, and it defines four methods.  

  • 00:45:14 We can define this abstract class method like this  return. Okay, let's say "white". Okay, this will  

  • 00:45:26 work. By the way, I need to. If I make it a method  like this, I have to mark it as virtual so that it  

  • 00:45:35 can it can be overridden. If I make it abstract  like this, then I can't it can't have a body.  

  • 00:45:45 Okay, so you can define body inside an abstract  class with virtual methods that can be overridden.  

  • 00:45:54 Or you can make it abstract and it won't have  a body. It won't have a body in method. Okay.  

  • 00:46:02 Okay, so for demonstration, let's  also have another class here as  

  • 00:46:12 abstract class with body having method.  And let's say virtual get color.  

  • 00:46:34 Okay, so both methodology is fine. Okay,  let's continue with our interface violation,  

  • 00:46:41 interface principle violation. So we have  I printer tasks and it has print, scan,  

  • 00:46:47 fax and print duplex methods. Interfaces can have  method implementation, but they can't have they  

  • 00:46:57 can't have fields, data fields like public int.  Okay, my property. Now it says that interfaces  

  • 00:47:07 cannot contain instance fields. Okay, so this is  also valid. Okay, let's return back to our topic.  

  • 00:47:17 So we have I printer tasks. And not  only that, we have. Okay, let's see.  

  • 00:47:28 HP laser jet printer, which inherits I  printer task interface. So interfaces  

  • 00:47:36 are like blueprints and we have to implement  each of the methods defined in the interface.  

  • 00:47:46 In the abstract class that we don't have to  implement all of them. Actually, that was also  

  • 00:47:52 another mistaken information that I have given.  For example, let's say we have abstract get color.  

  • 00:48:06 And these methods. Have to implement them, but. We  can also define a body for that method and. Now.  

  • 00:48:29 Oh, it was true, so in both cases  we have to implement both. Okay,  

  • 00:48:35 so let's just ignore that too. Okay, so I  printer tasks is inherited with HP laser  

  • 00:48:45 jet printer and now we are defining each one of  the methods and. You see, we have print, scan,  

  • 00:48:54 fax and print duplex. Each one of them, each  one of the defined methods is also used here.  

  • 00:49:01 However, let's say I also have another class  that inherits the I printer tasks. Interface and  

  • 00:49:12 this is liquid inject printer and in liquid inject  printer. We don't have fax method or print duplex.  

  • 00:49:19 Therefore, they are not implemented exception.  They are throwing not implemented exception.  

  • 00:49:27 And this is a violation of interface  segregation principle. Why? Because  

  • 00:49:33 we are inheriting an interface. But we are not  using all of the methods that it requires. Okay,  

  • 00:49:45 so how can we fix this problem? We can fix this  problem by. Splitting this interface into multiple  

  • 00:49:54 interfaces and implementing necessary  multiple interfaces in each class. Okay,  

  • 00:50:01 so let's first define this example. Then move to  the proper interface design. Okay, for example.  

  • 00:50:28 Okay, now fix this interface violation problem.  

  • 00:50:41 Okay, proper interface segregation.  

  • 00:51:03 Let's fix the name segregation, yes.  

  • 00:51:17 Okay. All right, so let's add another  class. And see the example proper interface  

  • 00:51:46 segregation. All right, let's copy paste.  The fixed interface class implementations.  

  • 00:52:08 Okay, so we did split the IPrinter tasks in  the first case in the first example into three  

  • 00:52:17 interfaces. The first one is IPrinter tasks.  It has print and scan. What does this mean?  

  • 00:52:24 This means that every class that inherits IPrinter  tasks interface will have these two methods. Okay,  

  • 00:52:33 so these are the basic methods that every  printer will have print and scan. Then we  

  • 00:52:40 have I fax tasks, which means that whichever the  class in inherits I fax tasks interface will have  

  • 00:52:48 fax method and whichever the class that inherits  I printer duplex tasks will have print duplex.  

  • 00:52:55 So since these are interfaces, we can have  multiple interfaces inheritance. However,  

  • 00:53:01 for abstract classes that you  can have only one implementation.  

  • 00:53:09 Yes. Okay. For example, if we define two abstract  classes, such as. Okay. And public abstract.  

  • 00:53:23 class ab2. Then our class can inherit only one  of them. For example, it can inherit ab1. And  

  • 00:53:36 it has to come before any interfaces like  this. However, if I also add ab2 here.  

  • 00:53:45 Then it will say that the base class cannot have  multiple base classes. I mean, the child class  

  • 00:53:53 cannot have multiple base classes. However, it  can have as many as interfaces as necessary.  

  • 00:54:01 Okay, so the HP laser jet printer will have both  print, scan, fax and print duplex methods. All of  

  • 00:54:11 them and the liquid inject printer will have only  print and scan, which are the very basic functions  

  • 00:54:17 of printers. Okay, so this is the corrected way,  the proper way of interface segregation principle.  

  • 00:54:30 Okay, now time to move the last one.  

  • 00:54:34 The last principle in the solid design principles  is what dependency inversion principle.  

  • 00:54:45 What is the dependency  inversion principle in C sharp?  

  • 00:54:49 The dependency inversion principle DIP states  that high level modules / classes should not  

  • 00:54:55 depend on low level modules / classes.  Both should depend upon abstractions.  

  • 00:55:01 Secondly, abstractions should not depend upon  details. Details should depend upon abstractions.  

  • 00:55:10 The most important point that you need to  remember while developing real time applications,  

  • 00:55:14 always to try to keep the high level module and  low level module as loosely coupled as possible.  

  • 00:55:22 When a class knows about the design  and implementation of another class,  

  • 00:55:26 it raises the risk that if we do any changes to  one class will break the other class. So we must  

  • 00:55:32 keep these high level and low level modules /  classes loosely coupled as much as possible.  

  • 00:55:38 To do that, we need to make both of them dependent  on abstractions instead of knowing each other.  

  • 00:55:45 Okay, so let's start with an example  to understand better. Okay. Okay,  

  • 00:55:55 I'm adding a button.  

  • 00:56:01 Violation of dependency inversion.  

  • 00:56:23 Let's click and oh, we also need to fix  this as proper Interface separation.  

  • 00:56:36 Okay. And then I can call. Okay, so let's add  a new class for dependency inversion violation.  

  • 00:56:55 All right. And in here, let's copy and  paste the code. Okay, we have a public  

  • 00:57:03 class employee and it has four attributes,  which are ID, name, department and salary.  

  • 00:57:15 And we have public class employee business  logic. Okay. And we have public class data  

  • 00:57:26 access factory. Let's paste it in above the  employee data access and. Okay. We also have.  

  • 00:57:45 Okay, one second. Here.  Yes. Now all is fixed. Okay.  

  • 00:58:01 So we have employee class, which holds the data of  each employee. We have employee data access class,  

  • 00:58:08 which implements the logic of accessing  employee data. You see, it has a public  

  • 00:58:15 method that returns employee data. It is named as  get employee details. It takes ID of the employee.  

  • 00:58:24 Then it generates an employee, an  example employee and returns it.  

  • 00:58:29 Okay. And we have two other classes,  which are data access factory.  

  • 00:58:35 It has a public static method that returns a  new instance of employee data access class.  

  • 00:58:45 Okay. We have employee business logic class,  which implements employee data access.  

  • 00:58:55 Which uses employee data access and generates  an instance of employee data access class in  

  • 00:59:04 the constructor. And it returns the details. Okay.  So how is this violating the dependency inversion?  

  • 00:59:19 Okay. Let's read it to find out. Let us  compare the above example with the dependency  

  • 00:59:29 inversion principle in C sharp. As per the  dependency inversion principle definition,  

  • 00:59:35 a high level module should not depend on low level  modules. Both should depend on the abstraction.  

  • 00:59:43 So first we need to figure out which one is the  high level module class and which one is the  

  • 00:59:49 low level module class. In our example, a high  level module is a module that always depends on  

  • 00:59:56 other modules. So in our example, the employee  business logic class depends on employee data  

  • 01:00:03 access class. So here the employee business logic  class is the high level module and the employee  

  • 01:00:09 data access class is the low level module. So as  per the first rule of the dependency inversion  

  • 01:00:16 principle in C sharp, the employee business logic  class / module should not depend on the concrete  

  • 01:00:22 employee data access class / module. Instead,  both the classes should depend on abstraction.  

  • 01:00:29 The second rule of the dependency inversion  principle state that abstractions should  

  • 01:00:34 not depend on details. Details  should depend on abstractions.  

  • 01:00:39 Before understanding this, let us first understand  what is an abstraction. What is abstraction? In  

  • 01:00:47 simple words, we can say that abstraction means  something which is non concrete. So abstraction  

  • 01:00:54 in programming means we need to create either  an interface or abstract class which is non  

  • 01:00:59 concrete so that we cannot create an instance  of it. In our example, the employee business  

  • 01:01:04 logic and employee data access are concrete  classes that mean we can create objects of it.  

  • 01:01:11 As per the dependency inversion principle  in C sharp, the employee business logic high  

  • 01:01:16 level module should not depend on the concrete  employee data access low level module class.  

  • 01:01:23 Both classes should depend on abstractions,  meaning both classes should depend on either  

  • 01:01:28 an interface or an abstract class. OK, so let's  see how employee business logic is depending on  

  • 01:01:35 concrete employee data access in our application.  And we are right away seeing it. So you see,  

  • 01:01:43 OK. OK, as you can see, it is dependent on the  concrete instance of employee data access class  

  • 01:01:53 with here. And that is a violation of dependency  inversion principle. So we need to modify our  

  • 01:02:05 logic with abstraction abstract classes or  interfaces. Instead of depending on concrete  

  • 01:02:15 instance of a class. OK, so let's make an  example of this with violation. Actually,  

  • 01:02:41 that's the point is yes.  

  • 01:02:49 Yes,  

  • 01:03:09 OK, so let's also see the proper fixed  version of the dependency inversion. Right,  

  • 01:03:23 it will be proper dependency inversion.  

  • 01:03:35 OK, and let's add another class and name it as  

  • 01:03:47 proper dependent version. OK, so how are we  going to separate? We are going to separate it as  

  • 01:03:59 an interface IEmployeeDataAccess which  has employee get employee details method.  

  • 01:04:06 And we are going to have. OK, employee data  access class which inherits IEmployeeDataAccess  

  • 01:04:14 interface. We have data access factory  which still has the same method and we have  

  • 01:04:33 employee business logic. You see, in this case,  it has a field of IEmployeeDataAccess. OK, and  

  • 01:04:50 IEmployeeDataAccess is an interface. Therefore,  it is using the interface instead of concrete  

  • 01:05:04 instance of a class. So employee data access was  a class. Therefore, this was a concrete instance.  

  • 01:05:13 However, in here we are just using the interface  instead of a concrete instance of a class.  

  • 01:05:22 And this is the proper way of  doing dependency inversion. OK,  

  • 01:05:35 that's it. We have implemented the dependency  inversion principle in our example where the  

  • 01:05:41 high level module employee business logic and  low level module employee data access depend  

  • 01:05:47 on abstraction IEmployeeDataAccess.  Also abstraction IEmployeeDataAccess  

  • 01:05:54 does not depend on details employee data  access, but details depend on abstraction.  

  • 01:06:01 Advantages of implementing the dependency  inversion principle in C sharp.  

  • 01:06:07 Now the employee business logic and employee  data access classes are loosely coupled classes  

  • 01:06:12 because employee business logic does not depend  on concrete employee data access class. Instead,  

  • 01:06:18 it includes a reference of IEmployeeDataAccess  interface. So now we can easily use another  

  • 01:06:25 class that implements IEmployeeDataAccess with  a different implementation. OK, this is it. And  

  • 01:06:34 let's also make an example of this. Proper  dependency inversion. And we have IEmployee logic.  

  • 01:07:02 And now when we run our  application, it will compile.  

  • 01:07:09 OK, if you have any questions, you  can join our Discord channel. Also,  

  • 01:07:19 I will upload this into a GitHub repository  and I will put the link of the repository in  

  • 01:07:25 the description of the video. So make sure that  you check it out. Thank you for watching. I hope  

  • 01:07:32 you have enjoyed. Please make a comment and let  me know what you think. Hopefully see you later.

Clone this wiki locally