Design Patterns: Liskov Substitution Principle Explained Practically in C# (The L in SOLID)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
when you're writing code are you doing it right that's the question that worries a lot of people and should probably be at least something you think about design patterns are best practice concepts that we can implement into our code to make it better in some way think of them as guardrails to keep our codes safe in today's video we're looking at the third entry in the famous solid principle the L stands for the Liskov substitution principle we're gonna dive into what that means how I to change our programming practices and how far we should take it for those of you who don't know me my name is Tim quarry and it's my goal to clear up the confusion and frustration around learning c-sharp because learning software development shouldn't be so hard if that sounded something would interest you I think you'd benefit from subscribing to my channel and also from join my mailing list the mailing list is where you get exclusive content and insider access you can find a link to join a mailing list in the description below so let's talk the conversation on the list cough substitution principle which we're gonna call LSP from now on by looking at some code I could do a nifty PowerPoint for you and show you fun pictures but I think it's best to show it in a practical manner so here I have a project I've created in visual studio in c-sharp now the principles of this video actually apply to any software development language but since this channel focuses primarily on c-sharp that's the language will use the code I have here is rather simple I have a console application right here that demonstrates the use of creating different employees so I have right here the creation of a simple employee let's call them Tim Corrie here I have the creation of a manager which is a type of employee and then down here I have a class library which actually has three different types of employees we have a standard employee which the employee has a first name a last name a manager a salary and then a couple of methods here a sign manager and calculate per hour rate then we have the manager which inherits her employee and overrides the calculate per hour rate and also has a additional method generate performance review then find a CEO also inherits our employee it has the overridden calculate per hour rate it also has the assign manager overridden but it just throws an invalid exception because the CEO has no manager and then it has also the generate performance reviews and the fire selling method all right so that's the basic overview of our little program right here now the problem this program is it actually violates LSP so now that we have some code in front of us let's talk about LSP LSP States and this is the definition if s is a subtype of T then object of type T maybe you're placed with outage of Type S without breaking the program so that's the really simple definition which if you think it's simple you should read the the larger expanded versions because they use fun words like covariance and contravariance preconditions post conditions invariants a lot of big words there but let me see I can break all this down for you by illustrating what the rule is really saying here's the very very basics of it here I have an employee the base type employee is called employee then I'm creating and doing some things with that employee LSP says I should be able to use manager here without breaking anything here now and here's one of the key things here yes this calculate per hour rate will be different in how it calculates the rate that's okay but what it can't do is it can't throw an exception where the employee would not have so for example let's start out let's put it back to employee I'm gonna run this application just to show you that it does work and all it does is it creates the employee in a manager and at the end it says the employees first names that's Tim Tim salary is and then it gets my salary $16.50 an hour if I were to change that and put in manager because manager is a subtype of employee I should be able to replace employee with manager if I run this again it works and now it just says Tim salary is 27 dollars and 75 cents an hour so that worked anything great well let's do it one more time but this time let's say CEO I run this and throws this exception the CEO has no manager so let's stop and look here I was assigning a manager to this employee well because I'm either am a CEO they I can't assign a manager therefore it blows up and that's what LSP is saying is a problem it's saying if you have a child type or inherited type like manager which inherits from employee or in this case our issue was CEO this CEO should be able to be put in place of wherever you see employee and not break the application and it did it broke the application because a CEO has no manager so that's our problem so that's the very very basics by the same time that's the whole point of LSP now let me just touch for a minute briefly a couple of things the covariance and contravariance you'll hear those words turn around so the covariance talks about the return type of a of a method so it's saying if you have a return type that returned to can't change which that's really hard to do in c-sharp anyways if you're inheriting so right now these don't have return types but what if I said you know what for for manager I actually want to return that value as well so I return a decimal well that won't work like that that wouldn't really work because it's not matching up with what it's overriding that calculate per hour rate okay now there is a way of doing it with interfaces so I'm not gonna say it can't be done c-sharp it can be but it's really hard and quite frankly you probably won't get into this okay but just know that when you see that when you see them say something about covariance it's just talking about changing that return type and contravariance just talked about the input type so if I change this into a double say that you can't do either but again you'd have to have some kind of interface in order to get that to work the way you're intending so just know that those big words out there we're kind of already covered for those all right and the other thing is we can't have preconditions and postconditions so it's saying for preconditions you cannot strengthen them okay what that just means is if when let me just point out a method here we have this method calculate per hour rate this is an employee class and it takes in a rank right now it does no check on this int to make sure it is a positive number to make sure it's within a range that stuff if in the manager for us calculate our calculate hours rate if I said something like if rank is less than zero or rank is greater than five throw new the say exception whatever you can't do that okay what would happen is it would work for employee but when I replaced manager and put that in a place of employee it might break and so you can't strengthen preconditions and also you cannot weaken post conditions meaning you cannot allow be really strict in what comes back here so if we say it has a returning value if we said what has to return the value inside this range well you can't weaken that then for the child item so big words that don't really apply in about 99% of cases especially in c-sharp but just know that they're out there and those are kind of expanded on the rules but basically it all comes back to is the idea that you can't change how this functions radically okay you can't make big changes to how this base class works and one of those changes that we're going to get into is this one right here we have you a sign man sir one of the kind of sub rules or interpretations or expand version of the LSP says you cannot return new exceptions well this right here is a new exception okay so that is something unexpected that wasn't returned by the original assign manager method and the reason why we can't return new exceptions which we can even do it in other methods like if we have an if statements as well again if you know rank is well actually a manager if we said if rank was less than zero the throw exception we can't do that the reason why is because if we're not looking to catch those exceptions that on the employee then if manager or CEO throws an exception it'll be an unhandled exception and so it's going to crash our application in unexpected manner and that's really what we're talking about is unexpected behavior so if you expected to work in one way and CEO works in a different way that's a problem and this really comes down to a correct view on inheritance this is where a lot of times what I do is I gravitate more towards an interface rather than inheritance now you can still have to an extent LSP applying to interfaces but it's really almost it doesn't almost but with inheritance the problem is that it's very easy to get tripped up okay we we say with inheritance you have to have an is a relationship so a manager is a employee okay and you say well a CEO is a employee yes and no it actually no and the reason why is because we're not just saying in the abstract sense we're saying based upon the information that we've assigned to the employee class so one of those is that we assign them a manager and they have this property called manager well guess what a CEO is not a person who has a manager therefore the CEO actually fails the is a relationship because they don't have a manager they wouldn't assign be assigned a manager and so that's where it really comes down to is LSP just kind of put a flashlight on our inheritance structure and saying this is how you tell that you're you doing something wrong it's saying look at this from the perspective of true inheritance and say is this really true and it's not and so really what should happen is we need to change our structure so we'll get to a minute well we'll work through how to to redo this so that we have and we still have some inheritance or some some shared code base by the same time we don't have this idea of inherits everything even the the incorrect things like this a sign manager but I think it's also a good time at talk about our previous lesson which was on OCP or open closed principle and let's look at the employee class so I have this base class called employee and I have some stuff in here and I want other classes to inherit from this to get the shared code base which is great but here's where the tricky part comes in in order for me to override the say assigned manager class or the calculate out per hour rate I have to make the method virtual so if I am going to down the road create a new class let's call that class janitor whatever reason janitor gets their own class that's a employee but maybe want a day a property a list of string called keys and it lists all the different keys they have for the building that's great but what if I want to in the janitor override something else well I have to make sure that item is marked virtual so I have to when I create this employee class think through anything that could be overridden and make sure a market is virtual because otherwise I'd have to come in here and modify this base class in order to add my new class which would violate the OCP principle the open-closed principle so that's a problem so just make sure that we are thinking this thing through that if you do i do inheritance and that does make sense for the situation that you think threw down the road how it might be used and make sure you apply virtual where it's important because otherwise your callers or your your children of that class won't be able to override a particular method in which case they're locked into doing it the same way that you're doing it either that or they're violating OCP by going in changing your base class so just let me think through kind of we're kind of building on each other here so this isn't saying and this is one of us seem to get a careful on this is not saying never use inheritance because it kind of feels that way sometimes because you're like oh man so many limitations I just won't use it that's not the answer but what it is hopefully gonna do is discourage you from using inheritance in the wrong way it should be clear that yes this is an inheritance situation this is truly a case of the the child is a parent is a parent class so like a manager truly is a employee so that's that's hopefully we're going to get to this this LSP principle is that we actually think through that process and make sure you lock in yes I'm gonna do it for the right reasons and I thought through these things because it violates the LSP then it's an it shouldn't be done so let's talk through how do we solve this issue how do we resolve this so it still has inheritance but at the same time is compliant with LSP the first time I'll point out is there are some things that are common with employees managers and the CEO their first and last name they all have it they all have a salary and we can calculate the per hour rate for each one of them so those are all things we have in common what we don't have in common is this manager line the assigned manager and then also notice the the manager class and CEO class both have this generate performance reviews okay so that's an extra method which by the way we inheritance this is fine and this is does not violate LSP at all because these they have an extra methods not in employee so if we swap out employee with CEO or manager that's fine they'll never even know what the fact that we have this extra method called generate performance review so it's not gonna break anything so instead we can actually make this a little better as well but let's start with the employee class now there is a shortcut we can do if you already have a class and you want to create an interface which is why I want to do if you on the class itself select it this is little lightbulb to the left or control dot will pull me down if you drop does menu one of the options in here is extract interface this is really convenient so I create a I employee interface and we'll leave it in the same spot notice I get to choose which items to bring along well I want to bring first and last name for sure not manager but salary you asked to calculate per hour rate but not to assign manager I hit OK and there's my interface done it's great so my interface being done actually collected employee notice I now implement the I employee interface and that's cool so now I can do is I can go back and actually create another interface so it's right-click on my demo library an add new item interface I'm gonna call this the I manager interface and I'll make it public and this is actually going to inherit from the I employee interface so an AI manager is an AI employee now a manager what they have access to is one more method which is generate performance review logic copy a signature here okay so now we have everything employee does Plus this generate performance review I create one more interface right click add new item interface I managed now I I debated in this title I also thought you know I MP on or I have boss or something like that but I managed seem like it it worked so I managed that also inherits from AI employee and with this one we're going to do is go back to our employee class and grab both the the manager so I'll grab that and then also we're going to come back to the employee class and grab the assign manager oops there we go and I'm going to do it here is I'm gonna change us to I employee instead of the employee and also the I employee manager right there okay so there we go so now we have three interfaces we have the employee interface which is the base interface which has just a stuff in common with everything then we have the eye manager interface which has that additional method we have the I managed interface which has the manager property and also the assigned manager method okay so now we can come back here and change up how our system works so instead of the manager inheriting from employee we could change it so they can implement the AI manager of manager interface the only problem is that we no longer bring in all that code which is a ton we have you know retains a ton all that code from employee so we have to implement the first-name lastname the salary and the calculates per hour rate so which is not great we've lost quite a bit here by doing that so instead we've got to make one more tweaking so we're going to do is right-click on demo library and add a new class right call this class let's call it base employee there's probably name for this but base employee works and this will be of type I employee so now on the employee class let's go ahead and find that again it's fall off a screen here okay copy and paste this whole thing for right now but we're going to take out the manager and a sign manager and we'll have just the these right here in fact I may even make this so that you have to override it I may make it abstract I probably won't I'll leave it this way and just say we have a the base employee has this kelly hours or per hour rate so there's a debate here because this changes in every one of our classes but I'm thinking that it won't change for the typical employee the just employee class so I'll leave this as virtual and have a base calculation for it so now employee we can do is actually inherit from the base employee and you won't need the first and last name we won't need the salary and you won't need the calculate per hour rate because that's the same as the base employee now we just have two extra methods or method in the property because we also implement the I managed interface and so you don't have an assignment due let's find out why ah here's why it's an AI employee not employee I employee and I employee and I can get rid of those extra ones that create for us always check your signatures so there we go so now that should work we've just inherited from base employee which brought in all the stuff it's common to all of us but we also implementer face so now I can call this a I employee because and base employee inherits my employee we can also call it base employee or I can call it I managed employee all right now show off how it's all working just a minute but let's go on to the manager which inherits for employee which we don't want anymore because employee has some extra stuff that doesn't necessarily work for us but let's look at a employee has a manager and assigned manager well so does a manager a manager has a manager and assigned manager so therefore that's that's okay so we can actually still inherit from employee which inherits from base employee and we also have this generate performance review which is part of the eye manager interface so you have both now then the CEO they are not an employee they inherit from the base employee but they're also the I managed manager not managed we take out this assignment and now we comply with both base employee and also the AI manager okay so life should be good let's just build it make sure we have any errors let me do that's fine what that error is go the error list and that's back at our program because we said employee a CEO is an employee learn not anymore but we can say you know what a manager is and that'll work if we run it Tim salary is twenty seven dollars and seventy-five cents an hour if we change it back to an employee that will also work so now we've done is we've changed our application over to be LSP compliant we have reworked our interfaces reworked our implementations and our inheritance so that we can kind of mix and match these things but at the same time whatever we say we implement we truly do in the correct manner so a manager truly does implement the employee class but it also has extra stuff which is fine and that's where the AI manager comes into play whereas the CEO does not implement employee it implements the base employee because base employee is the one that has all of the stuff in common with everything now one more thing before we go on and that is we have a space employee class but we never really want to use this directly so therefore it should be a public abstract class now I don't want to go too deep into abstract class here but essentially what this means is that this is a class you're going to inherit from but you'd never use directly so we would inherit from base employee but we'd never actually use it as a true employee Debi the more correct way of doing this but the one thing it does do is it does limit a bit our example so I'm gonna leave this off for just a bit they wanna show you if we were allowed to use this if this was something that made sense ok so just hang a first and last name a salary in the calculate per hour rate if that made sense for a type of employee then we come over here to our program CS and maybe what we do is change this over to base employee and of course we can't assign managers be all employees don't have managers we could do the rest and notice I'm actually assigning a new employee not a base employee but if I ran this it would still work if I were to change this over to base employee and run it it would still work if I changed it over to CEO it would still work and the reason why is because base employee is the parent class both the or all of the above employee manager and CEO classes they all inherit from the base employee and so therefore these are all children of base employee therefore they can be used in place of their parents base employee and not break or cause any unexpected functionality to happen so no new exceptions no tightening of preconditions no loosening of post conditions no covariance or contravariance issues essentially it just means it doesn't break anything when you use it and so that shows us that yes in fact we do have a correct implementation of LSP so let's go back to employee what's before I do that lets go ahead and over here go back in the abstract back in I just want to show you this is the one thing that abstract will do for us is if we have of new base employee I think oh no you can't do that because we can't create a we can't instantiate base employee but notice if I had that employee here no problem because it says I know what LSP is and how it works therefore any child class really is a the base class item so employee will work so we'll CEO so we'll manager because I know that I can expect the same thing have any of them so that's how it all works that's really the basics of LSP now we can get into some more fun stuff here for example we could do the I managed here and so we can have an a manager or we can have a CEO and it should work just fine now it's not be the saying object initialization can be simplified let's find out why rename manager to CEO no I want to do that and they're saying it's implied nope oh and I see a problem so it's saying hey CEO is not and I managed and that's because I made a mistake and I meant to say manager and that should not work and in fact it does so I can also come over here and say well I won I managed for this person and then come back over here and add the assigned manager because I managed has that and that's it I'm a scientist that also worked so now I can kind of mix and match these things and I know that if it's an I managed it's going to work the same way so even if I have a manager here while a manager is an I managed implementation therefore again it still works the CEO is an AI manager as well as a manager is therefore I can mix and match that as well no problem so you see how it gives us some flexibility here that we didn't have because we're correctly implementing LSP we have that ability to swap out items for their parent class or parent implementation without fear round break something now you did notice that the calculate per hour rate yeah that's different the salary is because a manager has a different salary calculation than a employee does or then a CEO does and so there is some implementation issues you get to think through but that's now LS P is talking about it's saying know that the child class can go in place with a parent class and not break your application now how you deal with the changes in those kind of values that's kind of up to you but that shows a true inheritance structure okay so try us out get to know it but basically what this is designed to do is teach you how to write good inheritance because way too often you find that you start down this path inheritance thinking oh I can share code and the idea of sharing code is all you're about then you're probably only get it wrong because a lot of things share code that doesn't mean they're related my desk chair has wheels and so is my car well if you think about it those two things both share an implementation they both have wheels that turn that doesn't mean they're related enough to have an inheritance structure just because two things have similar similar traits doesn't mean you have to have an inheritance structure instead what you might have is you might have a shared method that's called on a wheel turn that tells how wheel turns and maybe both a car class and the chair class use that method to demonstrate how wheel turns or to actually turn the wheel that's different and that's where a different design pattern comes into play called dry don't repeat yourself and if you find yourself doing repetitive code my first instinct is to look at dry not at inheritance and when you start learning about inheritance the first thing you see is everything inherits and everything else not really true but there is a case for it so for example if you look at a windows form project and you open up a windows form go to class look at what the class form inherits from and then follow that all the way down through there's both interfaces and implementation of parent classes and so there's both in play there so the is definitely a huge case for this it's just you have to do it right and figure out when is a CEO not an employee in our case a CEO is not employee if the employee included the assigned manager and manager property because then a CEO doesn't reapply it's not a CEO if they have those items so just think this through kind digest it don't freak out that's that's one of those things that when people look at this they're like oh my goodness LSP is so complicated that's got some rules this way it's so much so many names around it but if you come back think it through it's just trying to help you create a good inheritance structure deal with it that way look it over make sure you can you can pass these tests that it puts in place if you can you've probably got a good inheritance structure so if you have any questions loved to see in the comments below I'll try and answer as many as I can if you want the source code for this check out the description down below and be a link to my blog which has a source code for both the start of this demo and also the end thanks for watching as always I am Tim quarry
Info
Channel: IAmTimCorey
Views: 111,620
Rating: 4.9358025 out of 5
Keywords: .net, c#, c# training, c# tutorial, code, design patterns, design patterns c#, practical design patterns, programming, s.o.l.i.d, s.o.l.i.d design, s.o.l.i.d principles, s.o.l.i.d principles c#, s.o.l.i.d. design principles, solid, srp, tim corey, training, tutorial, visual studio, ocp, lsp, liskov substitution principle, liskov substitution principle example c#, liskov substitution principle example, liskov substitution principle uncle bob, liskov, solid liskov
Id: -3UXq2krhyw
Channel Id: undefined
Length: 39min 36sec (2376 seconds)
Published: Mon Apr 09 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.