Very helpful info. I've used inheritance and interfaces for years and never thought about all the criteria you've presented here. I liked the example of a "rental vehicle," which as you demonstrated, quickly fell apart as more business use cases (motorboat, sailboat, etc.) emerged. This happens in real life, as you know, which is why I always prefer to spend my first few hours (or days, even) on a new project learning about the business context or problem domain. Too many developers, who should know better, just want to just write code -- which is going to keep them at the "junior" level making rookie mistakes. "How well do you understand the business context?" might be one of the criteria I would add to your list when determining whether inheritance makes sense.
The people who don't study the business context and just code are hired to just code, not sure why you'd dunk on them. If however you're talking about freelance developers then I have to say I've never met one yet that is so incompetent that they'd ignore the business context of what they're developing.
to be fair that's why we have business analysts to do meeting with, they layout everything we need with future projections and implementations we'll need to worry about in the near or far future
Well done Tim! I am a senior developer with years of experience using these concepts and just when I think I already know the topic I always learn something new, or at least a new way of approaching it from you.
I've searched a lot after watching SOLID series to figure out how best to use interfaces. This excellent tutorial helped me a lot to better understand it. Thank you so much for shedding light on this.
Amazing explanation! Years ago I stumbled on a problem like this with a bank account class and I banged my head against the wall as to how it should be designed properly. But also you told as to how search for the stuff on the exact channel you need. I am very grateful for you for telling me this! My bad…I didn’t knew it.
I don't ever like videos and comment on them but I had to on this one. Because it breaks the topic down and gives examples of both in easy to grasp way to explain this murky situation between inheritance and interfaces. Thanks a lot from a new developer!
This is a very useful video. Thank you. It clarifies the difference of use between interfaces and inheritance with sufficient complexity, not just in theory.
Wow. Never new that about cars. I have never operated a car that used a physical key. Loved the video. Learned some good practices and I like the demonstrations of what to do and not to do.
Hey Tim, It was a good video. You made a good point when you said RentedVehicle was stretched too much and I think it would have broken Liskov substitution principle as well.
Great video. Generally, I do not use inheritance unless I have a real reason to do so. I deal with a lot of CRUD operations and, while I could contrive some sort of inheritance scheme, I don't because it adds needless complication to the code. As you pointed out, inheritance is not about sharing code but about hierarchies that frequently do not exist or only exist because they are contrived (although sometimes they do -- standard classroom techniques of animals/mammals/humans or canines or bats or whatever.) Something that many may not be aware of is that before object oriented code there was structured code. There were brilliant coders in the 1980's and they shared code through structured libraries. Object oriented code is not necessarily better than structured code, it is just different. However, in today's world understanding objects is a requirement unless you are doing systems programming in C or Assembler. Interfaces are a different matter. I use them all the time because I use dependency injection so that I can decouple classes and unit test my code. I do everything I can to break my code with these tests and I frequently succeed. I also liked your discussion of DRY. The real purpose of DRY is so that if you change a method one place you do not have to change the same method (repeated) or a similar method in your code. Thank you so much. I hope that others, including managers, are paying attention.
As always excellent and very informative. It will be nice if you can do another video on composition and it's implementation in C#. I always find it hard to understand the scenarios in which to use either of these
Hello Mr Corey. I also saw the videos about SOLID - the topic "Inheritance" vs "Interfaces" were already mentioned - very good lessons, thanks for that! However, I still have trouble figuring out what is the best use for "Is-A-Relationship" and "Has-a-Relationship" (Inhertiance vs. Composition). And: There are also cases where you can decouple the code with the use of delegates instead of Interfaces, or even with generics in fewer cases. I would appreciate a video showing best practice examples for these topics. Cheers
delegates and generics are just shortcuts for certain design patterns (depends on their specific use case and implementation). they aren't recommended if you want to write truly SOLID code. Many languages offer features like that if you are "lazy" but that doesn't mean that using them is always the best choice :) side note: especially if u work in a team where people usually aren't experts in a certain language then keeping to language features that all languages implement can be a huge advantage.
The conversation of modeling the real-world always comes up in our design team meetings. This video is worth watching for ALL dev levels because Interfaces are underutilization and this can cause a considerable amount of code refactoring when expanding systems into other industries...
This is great. I've come from basic, without any of the structure of modern languages. Good design and use of the features available is difficult, and often taken for granted by people familiar with them, for example the book I started with, which spent an age on things obvious to me but had little of this sort of thing.
Hi Tim @45:22 if (r is Truck t) - i dont get this - r is an interface "Irental" type and Truck t if of type "truck" how can you compare one against the other they are different types ??
r isn't an interface. An interface cannot be instantiated. Instead, the variable knows that whatever is inside of it implements the interface. The actual type isn't IRental, though. We had to put a concrete type inside of it. So, we are checking to see if the concrete type inside of r is of type Truck.
Polymorphic behavior = Parent over the child (attributes passed to the parent), Inheritance = Child over the parent (attributes passed to the child), Abstraction = Filtering out the calls/attributes, Interface = Patterns with definition towards attributes like that of a quilt.
I'm currently studying for my first ever junior dev interview and this is soo timely! Thanks for the greater understanding of OOP. :-) Now for a refresher on abstract classes and methods...
Tim, what is your stance on combining Interfaces? for example would you create an interface like this IRentalCar : IRental, ICar ? i keep getting sucked into putting all my inheritance in combined interfaces. do you think this is bad practice?
Would you agree that inheritence can be the result of refactoring multiple classes that repeat their code? Imagine I have 4 classes that evolved over time because we've added more and more features to our product and now we see oh hey we have repeated code, lets create a base class and inherit from it? Instead of creating a base class right at the beginning, make it a result of refactoring. Or am I wrong? I think this way I dont get into the problems from minute 24:30 where you say oh now this method doesnt make sense anymore to be in the base class.
Hey Tim,thanks again for this great video. I still have a small question though, at 35:00 when you are trying to show the inevitable repetition that interface brings, why can't we just put those three properties into a rental class, and just inherit from this base rental class? Just imagine if we need to add a new property like say "PriceRange" into the rental interface, don't we have to change all the classes that implemented this interface?
Oh, I see multiple class inheritance is not allowed in C#, so classes have to derive from one single base class, that makes much more sense why we have to use interface now. Thanks for this great example
So if we had the ability to inherit from multiple classes in C# (which we don't), that would basically replace interfaces? (except for the fact that interfaces are better to use for concepts that are not related to each other in a way that makes sense)
Great example, thank you. I was wondering, how would you design the database for this rental scenario? Would you rather have one "big" table that holds all rentals, or one separate table for each concrete implementation of IRental?
It depends on what type of database I am using. If I am using a SQL database, I would probably have one rental table but then I would have a table for each type of IRental item. Those items would refer back to the rental table's id to link them to the main table. That's just a thought off of the top of my head. I would have to test it out to see if it is the best idea. If I were using a MongoDB database then I would just store the objects with their data in one collection. We could break them back out into various models when we get them back to C#.
This is sp helpful. The place I am getting stuck is how I would bring in my NoSql data and know which object to use to import it. How do I store a new sail boat in a NoSql db and then bring it into memory in the right SailBoat object?
Hello Tim, is there a simple way to explain where to use inheritance and where to use Interfaces. It appears that both are used in various locations of a project which is something I think I need to understand. I think this is an important question that needs to be asked during the initial design phase of every new design project. Also, it looks like the biggest takeaway message is that multiple interfaces can be used in single classes while inheritances really cannot.
There are a few principles to follow. First, default to interfaces. Make yourself prove why you should use inheritance in a situation (not the reverse). Second, make sure that any inheritance follows it the "is a" relationship (car is a vehicle where car is not a truck). Third, don't try to use inheritance as a code-sharing-only option. Don't forget that we can share code by just creating another class that the initial class calls. No need for inheritance. Fourth, don't use inheritance just to pass down structure. If there is no code shared, why wouldn't you use an interface? The bottom line is that this is always going to be subjective in a general sense. It is only when you get to a very specific situation where you can determine what is best. That takes a lot of practice. Defaulting to interfaces won't burn you. Defaulting to or overusing inheritance will burn you.
@@IAmTimCorey thanks Tim for taking time out to help me! I see that’s your practice when you are creating your projects and tutorials. Just needed a deeper insight
Hi Tim, thank you for your help. I have one doubt: -I practically have one base class with 4 properties, but there are other properties that each of them should be added only if the user enable that in settings,should I do as many interfaces with only one property as are other properties and construct different implementations or would you have another idea? Thanks in advance.
Typically, you don't add properties based upon a user's choice. That sounds more like a set of boolean properties or a Dictionary of options. You shouldn't need multiple classes.
@@IAmTimCorey Hi Tim, thank you for your response. I have a done a class with all properties and one dictionary that has the name of property like key and if is enabled like value and i pass to classes that need those settings, is a good idea?
A beginner C# developer here ! What if I create Rental as a base class and inherit "LandVehicle" and "WaterVehicle" from it. Not only both of the derived classes would have access to the "Rental" class but also they can implement their own unique methods inside their classes. By doing this I can just inherit the "Rental" members from the Rental base class instead of implementing "Rental" class members in every single class which inherit from the Rental interface. Is this a possible solution for this problem ?
No, because not all LandVehicles are rentals. We sell some of them. Therefore, they would be inheriting from something that is no longer needed. Code repetition not the primary concern here. It is ok to have the repetition in order to maintain the proper hierarchy.
What if we want to add more properties to IRental, is that mean we have to go through all the files that implement the IRental and you think it is okay? To me, it is really hard to plan ahead. I am sorry i am still a noob!
I've been bit by the puts-you-in-a-corner issue a few times. Most of the time I reach for inheritance, I'm wrong. I can't remember the last time I legitimately needed it.
Hi Tim, foremost, thank u for the great video and for your time. Personally, I don't like having the props repeated as in BetterOODemo. Could be a valid approach to create a base abstract class and implement the interface (IRental in this case)? With that, the other classes can inherit from this base class and override the methods that have a different logic. Did you see any downsides with this approach?
Then your classes would all have to be rentals, which would not apply if you decided to sell some of the older vehicles (a common practice). Repeating props is not a big deal. Be careful not to let preferences impact performance.
Sailboat is where you switch to "real" C++ and forget about limitations in languages on multiple inheritance; inherit from Vehicle and Motorized. :) Interfaces is a lukewarm response to a lack of multiple inheritance in framework languages. And in BetterOODemo, how to deal with bike? Or your matchbox car? It can be rented but no engine. These specifics will break any OO concept with or w/o interfaces just as it did in simple framework OO. The problem that I have with interfaces is the people start with interfaces. Great. Any future change now requires changes and functionality to every class that inherits from it. I have to answer the question of the additional element for every class; which still may vary. And your example about code reuse assumes your adding simplistic properties. My programs are rarely simple CRUD type classes. I see your point about the complexity of the thing matters, but it still requires repetition. Not being a violation of DRY is just an opinion/interpretation; IMO :) Changing types in the future could be a pain based on usage. But, thanks for sharing. Always like to hear how people deal and feel about subjects.
Ive not finished the vid yet youre just adding the truck for me, but from reading ahead in the comments a bit, if you stopped the abstraction of RentalCar to LandVehicle, added the truck as a style in your enum and allow cars to have stuff like empty load capacity etc, then create WaterVehicle, LandVehicle, AirVehicle, etc, amd thwn wrap the logic about the rental and inventory information and the person renting it, the cost etc into a RentalContract class that contains a Vehicle of any type, plus this info. What do you think of this pattern? First time viewer btw enjoying the vid so far
Aha, it seems you ended up doing this. Even used the bad LandVehicle name i didnt like either! Maybe SelfPropulsionVehicle and PassivePropulsionVehicle or something. That might work better to genericise.
Just as a final comment, the reason id make the rental contract a class at the top is because you probably will have to manipulate and maybe query or store that data (to a file, db etc) I think itd be fair to do a rewrite if you syarted renting TVs etc, or split those off into their own programs with libraries and glue logic apps if you rewlly must. But i think having different systems for elelectronics, vehicles etc with very little shared abstractions - just the rental contract basically has to glue the concepts
What happens if we use the new “UA-cam Thanks” feature? Do you actually get the money it costs to buy the celebration things? Or does it just highlight your video?
Hi! Great content. Greetings from Argentina. What do you think about asking for implementation type check when working with interfaces? Doesn't it makes the client to know about the specifics of the implementation? I've been strugling with that idea recently.
I would prefer to avoid checking the implementation type and instead use multiple interfaces to handle the cases where the implementation is different enough to require checking. For example, a toy car and a real car can might have the interface IHoldsPassengers. However the passengers in a toy car are different to the passengers in a real car, so instead I may use a new interface IHoldsToyPassengers for the toy car so that I don't need to check whether the car is a toy or not. The interface itself becomes the checking point and the client doesn't need to know any details about how the interface is implemented. Interested to know if you had any other thoughts on this one.
@@LukeCloudrunner Well, I took an aproach similar to yours. My case was about an order creation process where items could be related to products, generic items non product related, discounts, combos, etc... Each one of them having different rules and data, but sharing part of that data by being "order details". At first, I created an IOrderDetail interface and passed an array of IOrderDetails to the order creation. But then i was checking types of elements for logic implementation and persistance. So I decided to create an "OrderCreationRequest" object that have a method for each detail type like "addProductDetail" or "addDiscountDetail". That way I can tell the clients of the order creation process which details can they pass, getting rid of the type checking.
Why do you choose to precede the interface with an "I"? Do you not know that it is an interface by the text color /if you hover on it? I just got curious since i think i read in clean code that using the "type" in the name is unnecessary but i am not sure myself.
Using "I" for an interface is an industry standard. The reason for this is not to signal the type like "str" or "lng" used to for variables (Hungarian notation). Instead, it is to clearly identify two different things (interface vs inheritance) when seen after the class. Remember that you can only inherit from one class and order matters. This way, we quickly know if the class inherits from another class or if it only has interfaces. I know IDEs make this easier to understand, but remember that you aren't always reading the code in the IDE. Sometimes you read it on GitHub or in a text editor.
@@IAmTimCorey Thank you very much Tim for your elaborate reply, I am very grateful :D And very good points aswell. Loving your videos and will continue watching them. :D
The choice between inheritance and interfaces can be tricky sometimes. Experience and domain knowledge can be helpful sometimes. Below is my two cents. If we want some external library classes to have same behavior in our code logic, we are quite sure using interface is the better way because external library classes are not inherited from our base classes. We can create a class inherited from external library class and implements the interfaces we want. Interface is more flexible but have to write own implementations. One of the ways to reduce this shortage is use some default implementation classes like RentalHelper and reuse the function inside. Interface should be as simple as possible. It is a poor design if an interface has too many properties and functions. This interface should be splitted to smaller interfaces. Try to make one interface serve one purpose only. Inheritance still have some other advantages also like better grouping and understanding of class hierarchy, and able to encapsulate and share private/protected members within its children only.
Interfaces should be as big as you need them to be and no bigger. That may mean that they are rather large. It all depends on the situation. Trying to make them too small means you will need to be utilizing casting later on to get access to the other desired properties and methods that another interface has in it. As for the default implementations, DO NOT DO THAT. The default implementations are not designed for you to use them like inheritance. They are only there to protect your existing classes from breaking changes. If you use the default implementation as a "multi-inheritance", you cause a lot of problems in your application and you incur a lot of casts as you switch between interfaces in order to get access to those methods.
Hi Tim, interesting video, thanks for sharing this knowledge! Sometimes I face the problem that (following your example) IRental would need some common logic. For example when setting the CurrentRenter property we would like generate internally some ID from that (i.e. the setter needs some logic implemented). How would you handle this situation? If we follow what you suggest at the end of the video about code sharing, then the actual call to the common shared code would be duplicated in each IRental property implementation… Or in this case should we create a base class "Rental" which implements IRental, and then LandVehicle would inherit from it?
I understand this is just an example but for all examples provided, this entire requirement can be resolved in the data layer with entity relationships. Very little needs to take place in the methods.
No, that wouldn't resolve anything. StartEngine and StopEngine have nothing to do with a data layer and creating entity relationships in the data layer would not solve the issue of using various types in one list.
@@IAmTimCorey your various "types" in this example are basically data collections that can be related or have multiple types of data in a single table with a "Type" column as an FK. If you want a column to be optional, just make it nullable. "Start" and "Stop" engine are also kind of impractical examples for a rental company, which, in this example, is just returning some text after a simulation. That could be done with a stored procedure. I'm not trying to criticize your lesson. It is very well done, with one exception. There are times when you speak quickly and kludge some words together. A native English speaker might still fill in the gaps but many non-native speakers might find it difficult to actively do that. My critique is mostly for me to wrap my mind around the concept. WHY would we want to do things this way? I'm trying to evolve out of my hard-set database background and learn better ways of doing things but am finding it challenging to understand that through this example. A database table schema structure allows for multiple inheritances. Another concept I have not understood about OOP. Why limit the inheritance to one?? Things are so simple in the DB world. Why is this so overly complicated?
It's a very nice video, but i can't get one small thing - why we can't take one abstract base class instead of IRental. Yes, i saw some comment below this video with the almost same question, but answer always about "We can't use multiple inheritance in C#", but where will be this multiple inheritance? One base class (we can call it RentalObject) and his childs - Landvehicle and Sailboat (better call with different name but not about it here). And landvehicle will have it's own childs - car, truck, etc. If we want some flexibility we can add some interfaces and combine it. Please, tell me where i am wrong with that model (sorry for my english). Yes, in this case inheritance just sharing properties, but this is a relationship and this will help us avoid repeating of code. Maybe here will be problem with SOLID, but (if it is, ofc, please tell me) main question about inheritance.
The issue is the relationship between the items. Is every boat a rental? Not if you are going to sell them when you are done. Then you have rentals in your inventory that you aren't going to rent. Then you have an issue because your core identity of each item you own is the fact that it can be rented, yet that's not always something you are going to do. Inheritance often puts you into a corner. My rule of thumb is to look at interfaces first and only use inheritance when it is totally clear and obvious. That means I pass up a number of opportunities to use inheritance. I'm ok with that. Don't think of inheritance as code-sharing. If that's all you are concerned about, create a helper class and call it from each class. You could create a RentalInfo class that has all of the rental information. You could then use it as a property on each rental item in your inventory. You could set it to null when you aren't renting the item. There are a lot of ways to share code without using inheritance.
Whats the difference, when i can rename "interface" into "class" and "IRental" to "Rental". What is the purpose to use a interface then? Seems like nobody can explain that rigth
I explained it in this video. You cannot inherit from multiple classes. You can apply multiple interfaces. For instance, Microsoft provides us with the IDisposable interface. If you implement it, you can use the using directive to properly dispose of your class instance. If this was a class, we would have to inherit from it. That would be a problem.
You don't. You could have inheritance like this, though: ClassA inherits from ClassB. ClassB inherits from ClassC. In that way, ClassA has access to ClassB and ClassC methods, properties, etc. If you find yourself needing multi-inheritance (not like I listed above, but where Class A inherits from both ClassB and ClassC directly), you are probably using inheritance incorrectly.
Did I miss it? you have a SailBoat and a boat (with engine) on your old OODemo, but not in the new one. You may be able to create a SeaVehicle which you can inherit to child classes like the boats, problem is, you will have the same Engine issue between boats with sails and normal boats with engines. How do you decouple the idea of having an engine? you cant inherit from a SeaVehicle having an Engine, do you divide by SailableSeaVehicle and SeaVehicles?
At that point, you are dealing with a "valid" inheritance issue and yes, you would need to create the main class without an engine because a boat can be a boat without an engine. You could create a sub-class that is called MotorBoat or something that would have the engine options in it. This, though, is where you start to see that inheritance is not really about code sharing. You need to have a reason to create this complex hierarchy so unless it really adds value, don't include the engine at all in the parent class.
@@IAmTimCorey I have a weird idea, tho it could work... What about we use a composition with interfaces? Something like: public abstract class Vehicle { protected IModeOfPropulsion _modeOfPropulsion; //And other common stuff about vehicles though you may want to divide still between land, sea, etc vehicles. } public class Car : Vehicle { Car(IModeOfPropulsion propulsion) { _modeOfPropulsion = propulsion } } public interface IModeOfPropulsion { void StartPropulsion(); void StopPropulsion(); } public class Engine : IModePropulsion { //Implementation of Interface and how it starts or stops depending of the type of the propulsion. }
I found even with interfaces a person can be backed into a corner. I had the issue before. For example, I have interfaces for solitaire games. However, it became messy but could not create even more interfaces because was unable to come up with names. However, somehow I made it work. If some methods are not always needed, they just don't get called if I am creating a game that does not need them. In that case, raising exception is fine. Its also okay in some cases where if a method calls and does nothing, its okay because there was nothing to do. For the rental sample, if a person did not know enough ahead of time when they created the system, then it may not be a big deal if a startengine method was called. If there is no engine, then just won't do anything. In that case, it could be okay. Unfortunately, since naming is hard, some times if a person can't come up with better names, a clunky system can be better than no system.
Yes, you can definitely create too large of an interface. That's a planning problem. That's why the recommendation from SOLID (Interface Segregation Principle) is that you create smaller, composable interfaces instead of large, unmanageable interfaces. As for raising an exception when an unneeded method is called, while that's what you have to do, that's also a sign of a design failure. If at all possible, that needs to be reworked to not need that. I definitely think it is a big deal that you didn't think far enough ahead with an application that you worked yourself into a corner. While you cannot know everything, you can properly plan and build an application. Not overusing inheritance would have saved the developer in my example, even if they didn't know that we were going to rent sailboats. Trying to include rental information and vehicle information together in one inheritance structure was poor design. The solution is to use an interface for items that may not have a true relationship but that have related features. Inheritance should only be used for true relationships. Follow that principle and you will have very few cases where you have "extra" methods and properties. In fact, that should almost never happen.
I noticed that as years passes I use inheritance less and les. It is as if "inheritance should only be used in class libraries by class library developers" except in rare cases where keeping the natural clear-cut correspondence between entities in is-a relation in a domain and related design/implementation representation (i.e. classes with inheritance) feels so comfortable. Even in those cases, if I don't feel that mysterious comfort during implementation, I immediately give up inheritance. I favor use of interface more and more. Even within the same module...If a class, for instance, needs a lot of helpers for its functionality in the form of parent classes or subobjects or delegates etc, then it is best to have it one or more interfaces even for internal usage by its very close friends.
Thanks for the feedback. Tim believes in giving context for what he is teaching and that takes time. His goal is not entertainment or just to dump knowledge on you but true education. Someone more familiar with the topics can speed up the presentation with great benefit to them. Slowing it down or losing the key "Oh, that's why he..." moment is not a good option. It's a balancing act, right? Your feedback helps Tim find that mix, so thanks.
Interfaces provide a lot of benefits. For instance, here are two big ones: 1 - replacement of dependencies. For instance, Microsoft has set up all .NET web projects to have a built in logger. However, you will almost certainly want to replace it with a "real" logger at some point. You can do that by just adding your logger in Program.cs. You don't need to change any code, since all of the code uses an instance of ILogger from dependency injection. 2 - you can more easily unit test projects. If you have a method that writes to the database, you don't want it to actually write to the database. You need to mock the database connection. That is very easy if you are using dependency injection with interfaces. You just create your own implementation of the data access interface that doesn't actually write to the database. A bonus would be that you can do work on a class you don't know about. For instance, Microsoft provides the IDisposable interface. You can use a using statement to properly dispose of a class if it implements that interface. You can implement that in your own class and it will work with Microsoft's code.
Not a great solution. Let's make that more obvious - if you had an animal class, would you want "TrunkSize" to be on all animals? That's basically what we have here. If an Engine isn't a part of all of the children, it shouldn't be in the parent.
Just to elaborate on the point above, this would force you to do null checks and create new control branches on every single a method that receives a vehicle and does something with the engine. It would lead to messy code structure, especially if you do it for many properties, like e.g. lights, windshield etc. Not what you want.
@@IAmTimCorey I hope you are not considering renting animals :P In any case, yes the OOP inheritance concept has to make sense, but we are suppose to program for humans so at some point decisions have to be make. Otherwise, we should all work together to make the oop model of the univers that every can use ;)
A very practical rule of thumb I personally use is that when I hit the dot and let the intellisense help me out, if I see a property or a method that just shouldn't be there, that it doesn't make sense, my class design is wrong.
@@IAmTimCorey it was a great video, I was just making a joke about refactoring designs, and that the point is you never see it coming! Therefore it seems like concrete hierarchies will never have a long life span in an environment with that many unknowns.
I "never" use inheritence because I don't like to don't see what it's on my class with a quick look, so I use and abuse interfaces now with default interface implementation inheritence it's a things of the past for me
I would encourage you against saying you will never use inheritance. C# is an OOP language. Inheritance is one of its pillars. You ge the value of inheritance every time you use a class from Microsoft. There is a definite use for inheritance, you just need to make sure you don't abuse it. Not using it all is also an abuse. As for using default interfaces, that is definitely an abuse. They weren't meant to be used as inheritance. They were meant to allow you to extend an interface without breaking all of the current things that rely on that interface. Trying to use interface defaults for anything more is dangerous and will lead to problems in your code.
In a few years peope are gonna be like "what are you talking about? You just press the button on your dashboard or use your phone to start your car. There's no key, silly!" 😂
@@IAmTimCorey what do you mean? I just type in the name of the person I wanna call! What is this dialing you speak of? Cave man technology! 😂 Ty for the video, again, Tim! I started programming with C# a year ago, and now I write and run assembly code from WPF apps. Never thought programming would be this fun!
Hi Tim, thanks for the video. I don't mean to be rude, but you are doing inheritance wrong. You should never create something like RentalCar or RentalVehicle. You only need to create a hierarchy of Vehicles (the same way you do with interfaces) and a hierarchy of RentalContract or RentalService. Vehicles have nothing to do with rentals, they should not have any members or methods related to rentals, because they are just vehicles. They need to know how to move forward and backward, how many passengers fit in them, etc, but nothing related to rental stuff. On the other hand, RentalContracts need to know what they are renting (a vehicle, a house or whatever), the duration of the rental, how much money per day or month it costs, the name of the customer, etc.... all things related to rental contracts, and nothing related to the behavior of vehicles, engines, wheels or houses. I repeat, I don't mean to be rude, maybe you did it that way for educational purposes, but I think it's a bad example
I don't think you watched the whole example. I was demonstrating how doing inheritance incorrectly and forcing the relationship can lead you into a corner. That's why I redid the inheritance and interface structure at the end to properly set up a flexible structure that is workable well into the future.
@@IAmTimCorey Thanks for answering. Yes, I watched the whole example. Anything done incorrectly can lead you into a corner, and that was the case in the inheritance example. You would had never reached that corner if you had assigned properly responsibilities to each class, that's all I'm saying. There are another examples where inheritance can't give you a good solution and interfaces can, but I think this is not the case. An example with LandVehicles, WaterVehicles and AirVehicles, some of them implementing IEngineVehicle (Car, Motorboat, Airplane) and some of them don't (Bicycle, Sailboat, Glider), would have been a better example. It's just my humble opinion, I don't want to create a discussion. Cheers
Very helpful info. I've used inheritance and interfaces for years and never thought about all the criteria you've presented here. I liked the example of a "rental vehicle," which as you demonstrated, quickly fell apart as more business use cases (motorboat, sailboat, etc.) emerged. This happens in real life, as you know, which is why I always prefer to spend my first few hours (or days, even) on a new project learning about the business context or problem domain. Too many developers, who should know better, just want to just write code -- which is going to keep them at the "junior" level making rookie mistakes. "How well do you understand the business context?" might be one of the criteria I would add to your list when determining whether inheritance makes sense.
Excellent point. Thanks for sharing.
The people who don't study the business context and just code are hired to just code, not sure why you'd dunk on them. If however you're talking about freelance developers then I have to say I've never met one yet that is so incompetent that they'd ignore the business context of what they're developing.
to be fair that's why we have business analysts to do meeting with, they layout everything we need with future projections and implementations we'll need to worry about in the near or far future
Well done Tim! I am a senior developer with years of experience using these concepts and just when I think I already know the topic I always learn something new, or at least a new way of approaching it from you.
I am glad it was so helpful.
I've searched a lot after watching SOLID series to figure out how best to use interfaces. This excellent tutorial helped me a lot to better understand it. Thank you so much for shedding light on this.
Thanks for looking to Tim for help on the topic.
@@tomthelestaff-iamtimcorey7597 Just want to add this tutorial is also the best one to get the DRY Concept across. Worth watching several times.
Amazing explanation! Years ago I stumbled on a problem like this with a bank account class and I banged my head against the wall as to how it should be designed properly.
But also you told as to how search for the stuff on the exact channel you need. I am very grateful for you for telling me this! My bad…I didn’t knew it.
Thank you!
I'm always amazed at how you make complex information so easy to understand and how deeply you go into the subjects Tim.
Thank you.
This is video really deserves more views and likes!! Thanks for explaining this topic in a very clear and substantial way
You are welcome.
Danke!
Thank you!
Great video Tim, thanks for sharing, Composition over Inheritance when possible is my gold rule.
Thanks!
Thank you Tim. Not just the right answers, but more important in this case: the right questions. You provided both.
Thanks!
I don't ever like videos and comment on them but I had to on this one. Because it breaks the topic down and gives examples of both in easy to grasp way to explain this murky situation between inheritance and interfaces. Thanks a lot from a new developer!
Awesome! I’m glad it was so helpful.
Million thanks to the great teacher Tim !
You are welcome.
This is a very useful video. Thank you. It clarifies the difference of use between interfaces and inheritance with sufficient complexity, not just in theory.
Thanks for you support and endorsement.
Wow. Never new that about cars. I have never operated a car that used a physical key. Loved the video. Learned some good practices and I like the demonstrations of what to do and not to do.
Glad it was helpful!
After your SOLID series i started to wonder about this topic and it seems like you got an answer for everything :)
Thanks!
You are welcome.
You are a real man Corey great work you are doing
Thanks!
Great content dude. Keep up the good work. Greetings from Portugal 🇵🇹
Thank you!
Well articulated and explained. Thank you for your commitment to the community by sharing the knowledge continuously !
You are welcome.
Bro this is the best explanation for interfaces ever
Glad it was helpful and thanks for the endorsement.
Hey Tim, It was a good video. You made a good point when you said RentedVehicle was stretched too much and I think it would have broken Liskov substitution principle as well.
Amazing video for a novice programmer such as myself, all made clear and logic is on point and explained well 👏
Glad it helped!
it took me some time to understand how interfaces should be applied and so on. but this video, damn. great lesson, thank you for your work!
You are welcome.
Its the best video that ı have seen about inheritance and interface
Thank you! I’m glad it was helpful.
Pretty awesome to see you still uploading!
He has no plans to stop.
Great video. Generally, I do not use inheritance unless I have a real reason to do so. I deal with a lot of CRUD operations and, while I could contrive some sort of inheritance scheme, I don't because it adds needless complication to the code. As you pointed out, inheritance is not about sharing code but about hierarchies that frequently do not exist or only exist because they are contrived (although sometimes they do -- standard classroom techniques of animals/mammals/humans or canines or bats or whatever.)
Something that many may not be aware of is that before object oriented code there was structured code. There were brilliant coders in the 1980's and they shared code through structured libraries. Object oriented code is not necessarily better than structured code, it is just different. However, in today's world understanding objects is a requirement unless you are doing systems programming in C or Assembler.
Interfaces are a different matter. I use them all the time because I use dependency injection so that I can decouple classes and unit test my code. I do everything I can to break my code with these tests and I frequently succeed.
I also liked your discussion of DRY. The real purpose of DRY is so that if you change a method one place you do not have to change the same method (repeated) or a similar method in your code.
Thank you so much. I hope that others, including managers, are paying attention.
Thanks for sharing!
Hey Tim. Thank you much. Im learning from your videos so I can be a better Python programer. Your videos are awesome! My best regards from Argentina!
Great to hear!
As always excellent and very informative. It will be nice if you can do another video on composition and it's implementation in C#. I always find it hard to understand the scenarios in which to use either of these
Hello Mr Corey. I also saw the videos about SOLID - the topic "Inheritance" vs "Interfaces" were already mentioned - very good lessons, thanks for that! However, I still have trouble figuring out what is the best use for "Is-A-Relationship" and "Has-a-Relationship" (Inhertiance vs. Composition). And: There are also cases where you can decouple the code with the use of delegates instead of Interfaces, or even with generics in fewer cases. I would appreciate a video showing best practice examples for these topics. Cheers
delegates and generics are just shortcuts for certain design patterns (depends on their specific use case and implementation). they aren't recommended if you want to write truly SOLID code. Many languages offer features like that if you are "lazy" but that doesn't mean that using them is always the best choice :)
side note: especially if u work in a team where people usually aren't experts in a certain language then keeping to language features that all languages implement can be a huge advantage.
The conversation of modeling the real-world always comes up in our design team meetings. This video is worth watching for ALL dev levels because Interfaces are underutilization and this can cause a considerable amount of code refactoring when expanding systems into other industries...
Thanks for sharing.
34:22 why dont make IRental a class instead of an interface and just inherit from there too?
Thanks a lot for this Video Tim. It helped a lot at my current project. Reusing code instead of retyping rocks. ;-)
You are welcome.
This is great. I've come from basic, without any of the structure of modern languages. Good design and use of the features available is difficult, and often taken for granted by people familiar with them, for example the book I started with, which spent an age on things obvious to me but had little of this sort of thing.
Thanks for looking to Tim to expand your skills.
Great videos, really learn a lot from you. Thanks
Thanks for trusting Tim and looking to him when you need to know!
My pleasure!
Hi Tim @45:22 if (r is Truck t) - i dont get this - r is an interface "Irental" type and Truck t if of type "truck" how can you compare one against the other they are different types ??
r isn't an interface. An interface cannot be instantiated. Instead, the variable knows that whatever is inside of it implements the interface. The actual type isn't IRental, though. We had to put a concrete type inside of it. So, we are checking to see if the concrete type inside of r is of type Truck.
Polymorphic behavior = Parent over the child (attributes passed to the parent), Inheritance = Child over the parent (attributes passed to the child), Abstraction = Filtering out the calls/attributes, Interface = Patterns with definition towards attributes like that of a quilt.
Thank you @Timcorey
You are welcome.
Very helpfull, Understandable perfect talking. Thank you...
You are welcome.
11:50 anyway to set a shortcut to "move type to xxxx.cs" in a one shortcut click instead of going through the menu then clicking ?
Not that I know of.
@@IAmTimCorey thanks for answering, my greetings :)
I actually wondered about it recently, good timing!
Thanks for looking to Tim when you need or just "wonder" about things.
I'm currently studying for my first ever junior dev interview and this is soo timely! Thanks for the greater understanding of OOP. :-)
Now for a refresher on abstract classes and methods...
Good luck on your interview. Check out Tim's Dev Questions for other videos the help with your interview prep.
@@tomthelestaff-iamtimcorey7597 Just as a follow-up: I got the job! Thanks again for the encouragement and resources y'all have provided!
Thank you for making it very easy to process!
You are welcome.
Tim, could you let us know what`s your opinion about the idea "prefer composition over inheritance"?
Since I came across this I have been noticing that this principle is way bigger than just computer science. It holds true almost everywhere.
I agree with the statement. Just remember that the key word there is "prefer". There is a time for each.
Especially for modelling "relational" database entities. I avoid inheritance there even when it makes sense.
thanks for the video sir.
You are welcome.
Tim, what is your stance on combining Interfaces? for example would you create an interface like this IRentalCar : IRental, ICar ? i keep getting sucked into putting all my inheritance in combined interfaces. do you think this is bad practice?
This is very helpful, Thank you for sharing.
You are welcome.
Fantastic video. Thank you so much
You are welcome.
Would you agree that inheritence can be the result of refactoring multiple classes that repeat their code? Imagine I have 4 classes that evolved over time because we've added more and more features to our product and now we see oh hey we have repeated code, lets create a base class and inherit from it? Instead of creating a base class right at the beginning, make it a result of refactoring. Or am I wrong? I think this way I dont get into the problems from minute 24:30 where you say oh now this method doesnt make sense anymore to be in the base class.
It can be a refactoring step, but it doesn’t eliminate problems like I demonstrated since refactoring isn’t the end of future development.
Hey Tim,thanks again for this great video. I still have a small question though, at 35:00 when you are trying to show the inevitable repetition that interface brings, why can't we just put those three properties into a rental class, and just inherit from this base rental class?
Just imagine if we need to add a new property like say "PriceRange" into the rental interface, don't we have to change all the classes that implemented this interface?
Oh, I see multiple class inheritance is not allowed in C#, so classes have to derive from one single base class, that makes much more sense why we have to use interface now. Thanks for this great example
I am glad I was able to clear that up.
RelationShipKind {Has, Is, Implements}
Inheritance: Is
Interfaces: Implements
Composition: Has
So if we had the ability to inherit from multiple classes in C# (which we don't), that would basically replace interfaces? (except for the fact that interfaces are better to use for concepts that are not related to each other in a way that makes sense)
Yeah, the fact that interfaces allow us to apply them to non-related classes is a big reason why they are better than multi-inheritance would be.
Very good discussion! thank you!
You are welcome.
Great example, thank you. I was wondering, how would you design the database for this rental scenario? Would you rather have one "big" table that holds all rentals, or one separate table for each concrete implementation of IRental?
It depends on what type of database I am using. If I am using a SQL database, I would probably have one rental table but then I would have a table for each type of IRental item. Those items would refer back to the rental table's id to link them to the main table. That's just a thought off of the top of my head. I would have to test it out to see if it is the best idea. If I were using a MongoDB database then I would just store the objects with their data in one collection. We could break them back out into various models when we get them back to C#.
This is sp helpful. The place I am getting stuck is how I would bring in my NoSql data and know which object to use to import it. How do I store a new sail boat in a NoSql db and then bring it into memory in the right SailBoat object?
Tim, more of this please :0
Noted, thanks
Hello Tim, is there a simple way to explain where to use inheritance and where to use Interfaces. It appears that both are used in various locations of a project which is something I think I need to understand. I think this is an important question that needs to be asked during the initial design phase of every new design project. Also, it looks like the biggest takeaway message is that multiple interfaces can be used in single classes while inheritances really cannot.
There are a few principles to follow. First, default to interfaces. Make yourself prove why you should use inheritance in a situation (not the reverse). Second, make sure that any inheritance follows it the "is a" relationship (car is a vehicle where car is not a truck). Third, don't try to use inheritance as a code-sharing-only option. Don't forget that we can share code by just creating another class that the initial class calls. No need for inheritance. Fourth, don't use inheritance just to pass down structure. If there is no code shared, why wouldn't you use an interface?
The bottom line is that this is always going to be subjective in a general sense. It is only when you get to a very specific situation where you can determine what is best. That takes a lot of practice. Defaulting to interfaces won't burn you. Defaulting to or overusing inheritance will burn you.
@@IAmTimCorey thanks Tim for taking time out to help me! I see that’s your practice when you are creating your projects and tutorials. Just needed a deeper insight
Hi Tim, thank you for your help.
I have one doubt:
-I practically have one base class with 4 properties, but there are other properties that each of them should be added only if the user enable that in settings,should I do as many interfaces with only one property as are other properties and construct different implementations or would you have another idea?
Thanks in advance.
Typically, you don't add properties based upon a user's choice. That sounds more like a set of boolean properties or a Dictionary of options. You shouldn't need multiple classes.
@@IAmTimCorey Hi Tim, thank you for your response. I have a done a class with all properties and one dictionary that has the name of property like key and if is enabled like value and i pass to classes that need those settings, is a good idea?
A beginner C# developer here !
What if I create Rental as a base class and inherit "LandVehicle" and "WaterVehicle" from it. Not only both of the derived classes would have access to the "Rental" class but also they can implement their own unique methods inside their classes.
By doing this I can just inherit the "Rental" members from the Rental base class instead of implementing "Rental" class members in every single class which inherit from the Rental interface.
Is this a possible solution for this problem ?
No, because not all LandVehicles are rentals. We sell some of them. Therefore, they would be inheriting from something that is no longer needed. Code repetition not the primary concern here. It is ok to have the repetition in order to maintain the proper hierarchy.
Great video!
Thanks!
and what keyboard are you using? / i have brown "breakers" and a ducky one 2 TKL but i am thinking of changing it to a lower key cap one...
I use the Logitech MX Keys keyboard (not mechanical - it would be too noisy for video).
@@IAmTimCorey Wow nice thank you!! It looks very nice and has low profile keycaps too! :D
What if we want to add more properties to IRental, is that mean we have to go through all the files that implement the IRental and you think it is okay? To me, it is really hard to plan ahead. I am sorry i am still a noob!
I've been bit by the puts-you-in-a-corner issue a few times. Most of the time I reach for inheritance, I'm wrong. I can't remember the last time I legitimately needed it.
Thanks for sharing from your experience
Hi, could someone point me to the source code download links?? "down-below"?? where?? Thanks
Hi Tim,
foremost, thank u for the great video and for your time.
Personally, I don't like having the props repeated as in BetterOODemo.
Could be a valid approach to create a base abstract class and implement the interface (IRental in this case)?
With that, the other classes can inherit from this base class and override the methods that have a different logic.
Did you see any downsides with this approach?
Then your classes would all have to be rentals, which would not apply if you decided to sell some of the older vehicles (a common practice). Repeating props is not a big deal. Be careful not to let preferences impact performance.
Okay Tim! Maybe I've to do more research about this topic to better clarify it. Anyway, thanks for your point of view 😊
So what do you do with a rental boat? It has an engine you can turn on and it's not a land vehicle.
Hi, thanks for the video. I have a question. What's the equivalent of "if (r is Truck t) {}" part in VB ?
Do I need to cast it ?
Not sure. I haven't kept up on my VB. Sorry.
@@IAmTimCorey Okay, no problem.
Sailboat is where you switch to "real" C++ and forget about limitations in languages on multiple inheritance; inherit from Vehicle and Motorized. :) Interfaces is a lukewarm response to a lack of multiple inheritance in framework languages. And in BetterOODemo, how to deal with bike? Or your matchbox car? It can be rented but no engine. These specifics will break any OO concept with or w/o interfaces just as it did in simple framework OO. The problem that I have with interfaces is the people start with interfaces. Great. Any future change now requires changes and functionality to every class that inherits from it. I have to answer the question of the additional element for every class; which still may vary. And your example about code reuse assumes your adding simplistic properties. My programs are rarely simple CRUD type classes. I see your point about the complexity of the thing matters, but it still requires repetition. Not being a violation of DRY is just an opinion/interpretation; IMO :) Changing types in the future could be a pain based on usage. But, thanks for sharing. Always like to hear how people deal and feel about subjects.
And I will check out your other videos related to DRY and other subjects. Thanks for sharing!
Thanks for joining the conversation and sharing from your experience.
Ive not finished the vid yet youre just adding the truck for me, but from reading ahead in the comments a bit, if you stopped the abstraction of RentalCar to LandVehicle, added the truck as a style in your enum and allow cars to have stuff like empty load capacity etc, then create WaterVehicle, LandVehicle, AirVehicle, etc, amd thwn wrap the logic about the rental and inventory information and the person renting it, the cost etc into a RentalContract class that contains a Vehicle of any type, plus this info. What do you think of this pattern? First time viewer btw enjoying the vid so far
Aha, it seems you ended up doing this. Even used the bad LandVehicle name i didnt like either! Maybe SelfPropulsionVehicle and PassivePropulsionVehicle or something. That might work better to genericise.
Just as a final comment, the reason id make the rental contract a class at the top is because you probably will have to manipulate and maybe query or store that data (to a file, db etc)
I think itd be fair to do a rewrite if you syarted renting TVs etc, or split those off into their own programs with libraries and glue logic apps if you rewlly must. But i think having different systems for elelectronics, vehicles etc with very little shared abstractions - just the rental contract basically has to glue the concepts
Smooth video.
Thanks for watching
17:39 isn't this a good example against using primitive types?
What happens if we use the new “UA-cam Thanks” feature? Do you actually get the money it costs to buy the celebration things? Or does it just highlight your video?
I do get the money (UA-cam takes a 30% cut, though).
Hi! Great content. Greetings from Argentina. What do you think about asking for implementation type check when working with interfaces? Doesn't it makes the client to know about the specifics of the implementation? I've been strugling with that idea recently.
I would prefer to avoid checking the implementation type and instead use multiple interfaces to handle the cases where the implementation is different enough to require checking. For example, a toy car and a real car can might have the interface IHoldsPassengers. However the passengers in a toy car are different to the passengers in a real car, so instead I may use a new interface IHoldsToyPassengers for the toy car so that I don't need to check whether the car is a toy or not. The interface itself becomes the checking point and the client doesn't need to know any details about how the interface is implemented.
Interested to know if you had any other thoughts on this one.
@@LukeCloudrunner Well, I took an aproach similar to yours. My case was about an order creation process where items could be related to products, generic items non product related, discounts, combos, etc... Each one of them having different rules and data, but sharing part of that data by being "order details". At first, I created an IOrderDetail interface and passed an array of IOrderDetails to the order creation. But then i was checking types of elements for logic implementation and persistance. So I decided to create an "OrderCreationRequest" object that have a method for each detail type like "addProductDetail" or "addDiscountDetail". That way I can tell the clients of the order creation process which details can they pass, getting rid of the type checking.
Why do you choose to precede the interface with an "I"? Do you not know that it is an interface by the text color /if you hover on it? I just got curious since i think i read in clean code that using the "type" in the name is unnecessary but i am not sure myself.
Using "I" for an interface is an industry standard. The reason for this is not to signal the type like "str" or "lng" used to for variables (Hungarian notation). Instead, it is to clearly identify two different things (interface vs inheritance) when seen after the class. Remember that you can only inherit from one class and order matters. This way, we quickly know if the class inherits from another class or if it only has interfaces. I know IDEs make this easier to understand, but remember that you aren't always reading the code in the IDE. Sometimes you read it on GitHub or in a text editor.
@@IAmTimCorey Thank you very much Tim for your elaborate reply, I am very grateful :D And very good points aswell. Loving your videos and will continue watching them. :D
The choice between inheritance and interfaces can be tricky sometimes. Experience and domain knowledge can be helpful sometimes. Below is my two cents.
If we want some external library classes to have same behavior in our code logic, we are quite sure using interface is the better way because external library classes are not inherited from our base classes. We can create a class inherited from external library class and implements the interfaces we want.
Interface is more flexible but have to write own implementations. One of the ways to reduce this shortage is use some default implementation classes like RentalHelper and reuse the function inside.
Interface should be as simple as possible. It is a poor design if an interface has too many properties and functions. This interface should be splitted to smaller interfaces. Try to make one interface serve one purpose only.
Inheritance still have some other advantages also like better grouping and understanding of class hierarchy, and able to encapsulate and share private/protected members within its children only.
Interfaces should be as big as you need them to be and no bigger. That may mean that they are rather large. It all depends on the situation. Trying to make them too small means you will need to be utilizing casting later on to get access to the other desired properties and methods that another interface has in it.
As for the default implementations, DO NOT DO THAT. The default implementations are not designed for you to use them like inheritance. They are only there to protect your existing classes from breaking changes. If you use the default implementation as a "multi-inheritance", you cause a lot of problems in your application and you incur a lot of casts as you switch between interfaces in order to get access to those methods.
@@IAmTimCorey Thanks for your advice. I will try to digest.
Can we investigate an often-used open source repository as a way to learn how the concepts are used in the real world?
I taught people how to do just that in this course: www.iamtimcorey.com/p/exploring-c-blazor-webassembly
Hi Tim, interesting video, thanks for sharing this knowledge!
Sometimes I face the problem that (following your example) IRental would need some common logic. For example when setting the CurrentRenter property we would like generate internally some ID from that (i.e. the setter needs some logic implemented). How would you handle this situation?
If we follow what you suggest at the end of the video about code sharing, then the actual call to the common shared code would be duplicated in each IRental property implementation…
Or in this case should we create a base class "Rental" which implements IRental, and then LandVehicle would inherit from it?
You can't have multiple inheritance.
Plus you would be making the same mistake with the different type of vehicles
Thank you!
You are welcome.
I understand this is just an example but for all examples provided, this entire requirement can be resolved in the data layer with entity relationships. Very little needs to take place in the methods.
No, that wouldn't resolve anything. StartEngine and StopEngine have nothing to do with a data layer and creating entity relationships in the data layer would not solve the issue of using various types in one list.
@@IAmTimCorey your various "types" in this example are basically data collections that can be related or have multiple types of data in a single table with a "Type" column as an FK. If you want a column to be optional, just make it nullable.
"Start" and "Stop" engine are also kind of impractical examples for a rental company, which, in this example, is just returning some text after a simulation. That could be done with a stored procedure.
I'm not trying to criticize your lesson. It is very well done, with one exception. There are times when you speak quickly and kludge some words together. A native English speaker might still fill in the gaps but many non-native speakers might find it difficult to actively do that.
My critique is mostly for me to wrap my mind around the concept. WHY would we want to do things this way? I'm trying to evolve out of my hard-set database background and learn better ways of doing things but am finding it challenging to understand that through this example. A database table schema structure allows for multiple inheritances. Another concept I have not understood about OOP. Why limit the inheritance to one?? Things are so simple in the DB world. Why is this so overly complicated?
It's a very nice video, but i can't get one small thing - why we can't take one abstract base class instead of IRental. Yes, i saw some comment below this video with the almost same question, but answer always about "We can't use multiple inheritance in C#", but where will be this multiple inheritance? One base class (we can call it RentalObject) and his childs - Landvehicle and Sailboat (better call with different name but not about it here). And landvehicle will have it's own childs - car, truck, etc. If we want some flexibility we can add some interfaces and combine it. Please, tell me where i am wrong with that model (sorry for my english). Yes, in this case inheritance just sharing properties, but this is a relationship and this will help us avoid repeating of code. Maybe here will be problem with SOLID, but (if it is, ofc, please tell me) main question about inheritance.
The issue is the relationship between the items. Is every boat a rental? Not if you are going to sell them when you are done. Then you have rentals in your inventory that you aren't going to rent. Then you have an issue because your core identity of each item you own is the fact that it can be rented, yet that's not always something you are going to do. Inheritance often puts you into a corner. My rule of thumb is to look at interfaces first and only use inheritance when it is totally clear and obvious. That means I pass up a number of opportunities to use inheritance. I'm ok with that. Don't think of inheritance as code-sharing. If that's all you are concerned about, create a helper class and call it from each class. You could create a RentalInfo class that has all of the rental information. You could then use it as a property on each rental item in your inventory. You could set it to null when you aren't renting the item. There are a lot of ways to share code without using inheritance.
@@IAmTimCorey Thanks for the answer. Didn't think about how the business logic might change and how the code would need to be changed.
Tnx a lot Tim
You are welcome!
So... what's the point of inheritance? Is there any situation where it is better than interfaces?
P.S. great video as always!
It can provide an efficiency when you truly have a relationship. The key is just not to abuse it.
Whats the difference, when i can rename "interface" into "class" and "IRental" to "Rental". What is the purpose to use a interface then? Seems like nobody can explain that rigth
I explained it in this video. You cannot inherit from multiple classes. You can apply multiple interfaces. For instance, Microsoft provides us with the IDisposable interface. If you implement it, you can use the using directive to properly dispose of your class instance. If this was a class, we would have to inherit from it. That would be a problem.
If need to Inherit more than one class what we will do?
You don't. You could have inheritance like this, though: ClassA inherits from ClassB. ClassB inherits from ClassC. In that way, ClassA has access to ClassB and ClassC methods, properties, etc.
If you find yourself needing multi-inheritance (not like I listed above, but where Class A inherits from both ClassB and ClassC directly), you are probably using inheritance incorrectly.
Thumbs up from india 👍
Thanks!
If only we could actually rent tanks, LOL! Jokes aside, thanks always Corey.
There is a place in Europe that rents tanks for goofing off. I’d love to try it someday.
How do interface and inheritances work with databases? If I use entity framework, then how does it map?
Here you can read about it docs.microsoft.com/en-us/ef/core/modeling/inheritance , cheers.
Did I miss it? you have a SailBoat and a boat (with engine) on your old OODemo, but not in the new one.
You may be able to create a SeaVehicle which you can inherit to child classes like the boats, problem is, you will have the same Engine issue between boats with sails and normal boats with engines.
How do you decouple the idea of having an engine? you cant inherit from a SeaVehicle having an Engine, do you divide by SailableSeaVehicle and SeaVehicles?
At that point, you are dealing with a "valid" inheritance issue and yes, you would need to create the main class without an engine because a boat can be a boat without an engine. You could create a sub-class that is called MotorBoat or something that would have the engine options in it. This, though, is where you start to see that inheritance is not really about code sharing. You need to have a reason to create this complex hierarchy so unless it really adds value, don't include the engine at all in the parent class.
@@IAmTimCorey Hey Tim!, thanks so much for the reply!.
@@IAmTimCorey I have a weird idea, tho it could work...
What about we use a composition with interfaces? Something like:
public abstract class Vehicle
{
protected IModeOfPropulsion _modeOfPropulsion;
//And other common stuff about vehicles though you may want to divide still between land, sea, etc vehicles.
}
public class Car : Vehicle
{
Car(IModeOfPropulsion propulsion)
{
_modeOfPropulsion = propulsion
}
}
public interface IModeOfPropulsion
{
void StartPropulsion();
void StopPropulsion();
}
public class Engine : IModePropulsion
{
//Implementation of Interface and how it starts or stops depending of the type of the propulsion.
}
I found even with interfaces a person can be backed into a corner. I had the issue before. For example, I have interfaces for solitaire games. However, it became messy but could not create even more interfaces because was unable to come up with names. However, somehow I made it work. If some methods are not always needed, they just don't get called if I am creating a game that does not need them. In that case, raising exception is fine. Its also okay in some cases where if a method calls and does nothing, its okay because there was nothing to do. For the rental sample, if a person did not know enough ahead of time when they created the system, then it may not be a big deal if a startengine method was called. If there is no engine, then just won't do anything. In that case, it could be okay. Unfortunately, since naming is hard, some times if a person can't come up with better names, a clunky system can be better than no system.
Yes, you can definitely create too large of an interface. That's a planning problem. That's why the recommendation from SOLID (Interface Segregation Principle) is that you create smaller, composable interfaces instead of large, unmanageable interfaces. As for raising an exception when an unneeded method is called, while that's what you have to do, that's also a sign of a design failure. If at all possible, that needs to be reworked to not need that. I definitely think it is a big deal that you didn't think far enough ahead with an application that you worked yourself into a corner. While you cannot know everything, you can properly plan and build an application. Not overusing inheritance would have saved the developer in my example, even if they didn't know that we were going to rent sailboats. Trying to include rental information and vehicle information together in one inheritance structure was poor design. The solution is to use an interface for items that may not have a true relationship but that have related features. Inheritance should only be used for true relationships. Follow that principle and you will have very few cases where you have "extra" methods and properties. In fact, that should almost never happen.
thanks
You are welcome.
I noticed that as years passes I use inheritance less and les. It is as if "inheritance should only be used in class libraries by class library developers" except in rare cases where keeping the natural clear-cut correspondence between entities in is-a relation in a domain and related design/implementation representation (i.e. classes with inheritance) feels so comfortable. Even in those cases, if I don't feel that mysterious comfort during implementation, I immediately give up inheritance.
I favor use of interface more and more. Even within the same module...If a class, for instance, needs a lot of helpers for its functionality in the form of parent classes or subobjects or delegates etc, then it is best to have it one or more interfaces even for internal usage by its very close friends.
Thanks for sharing.
I am really enjoying your videos, I have one suggestion is it possible to make the videos shorter
Thanks for the feedback. Tim believes in giving context for what he is teaching and that takes time. His goal is not entertainment or just to dump knowledge on you but true education. Someone more familiar with the topics can speed up the presentation with great benefit to them. Slowing it down or losing the key "Oh, that's why he..." moment is not a good option. It's a balancing act, right? Your feedback helps Tim find that mix, so thanks.
then what is the point of using an interface if the whole code works without inheriting the interface
Interfaces provide a lot of benefits. For instance, here are two big ones: 1 - replacement of dependencies. For instance, Microsoft has set up all .NET web projects to have a built in logger. However, you will almost certainly want to replace it with a "real" logger at some point. You can do that by just adding your logger in Program.cs. You don't need to change any code, since all of the code uses an instance of ILogger from dependency injection. 2 - you can more easily unit test projects. If you have a method that writes to the database, you don't want it to actually write to the database. You need to mock the database connection. That is very easy if you are using dependency injection with interfaces. You just create your own implementation of the data access interface that doesn't actually write to the database.
A bonus would be that you can do work on a class you don't know about. For instance, Microsoft provides the IDisposable interface. You can use a using statement to properly dispose of a class if it implements that interface. You can implement that in your own class and it will work with Microsoft's code.
What about making a class Engine and add a engine property that would be null for the sailboat or a bike
Not a great solution. Let's make that more obvious - if you had an animal class, would you want "TrunkSize" to be on all animals? That's basically what we have here. If an Engine isn't a part of all of the children, it shouldn't be in the parent.
Just to elaborate on the point above, this would force you to do null checks and create new control branches on every single a method that receives a vehicle and does something with the engine. It would lead to messy code structure, especially if you do it for many properties, like e.g. lights, windshield etc. Not what you want.
@@IAmTimCorey I hope you are not considering renting animals :P
In any case, yes the OOP inheritance concept has to make sense, but we are suppose to program for humans so at some point decisions have to be make. Otherwise, we should all work together to make the oop model of the univers that every can use ;)
@@kostasgkoutis8534 good point. I also try to reduce the if else statement (2 if's max, no else per function rule ;} )
A very practical rule of thumb I personally use is that when I hit the dot and let the intellisense help me out, if I see a property or a method that just shouldn't be there, that it doesn't make sense, my class design is wrong.
Drop that keel and centerboard, raise the mainsail, and you'll see if a sailboat has an engine 😁
I'll watch you do that from the dock.
Boss - You'll never believe it we just acquired a steam engine! 🙄🙄
Huh?
@@IAmTimCorey it was a great video, I was just making a joke about refactoring designs, and that the point is you never see it coming! Therefore it seems like concrete hierarchies will never have a long life span in an environment with that many unknowns.
RentalSailboat example was funny; Your RentalVehicle implies having engine, so you cannot inherit it or you need to make right abstraction
and, yes, you are not in a corner yet :)
I "never" use inheritence because I don't like to don't see what it's on my class with a quick look, so I use and abuse interfaces now with default interface implementation inheritence it's a things of the past for me
I would encourage you against saying you will never use inheritance. C# is an OOP language. Inheritance is one of its pillars. You ge the value of inheritance every time you use a class from Microsoft. There is a definite use for inheritance, you just need to make sure you don't abuse it. Not using it all is also an abuse. As for using default interfaces, that is definitely an abuse. They weren't meant to be used as inheritance. They were meant to allow you to extend an interface without breaking all of the current things that rely on that interface. Trying to use interface defaults for anything more is dangerous and will lead to problems in your code.
In a few years peope are gonna be like "what are you talking about? You just press the button on your dashboard or use your phone to start your car. There's no key, silly!" 😂
True. Kind of like "dialing" a phone.
@@IAmTimCorey what do you mean? I just type in the name of the person I wanna call! What is this dialing you speak of? Cave man technology! 😂
Ty for the video, again, Tim! I started programming with C# a year ago, and now I write and run assembly code from WPF apps. Never thought programming would be this fun!
Let me tell you how to fix the sailboat problem without changing the code.
Only rent sailboats that have an engine.
You joke, but that's how some companies do business. Change the business in order to fit the software.
Nice
Thank you.
Hi Tim, thanks for the video.
I don't mean to be rude, but you are doing inheritance wrong. You should never create something like RentalCar or RentalVehicle. You only need to create a hierarchy of Vehicles (the same way you do with interfaces) and a hierarchy of RentalContract or RentalService. Vehicles have nothing to do with rentals, they should not have any members or methods related to rentals, because they are just vehicles. They need to know how to move forward and backward, how many passengers fit in them, etc, but nothing related to rental stuff. On the other hand, RentalContracts need to know what they are renting (a vehicle, a house or whatever), the duration of the rental, how much money per day or month it costs, the name of the customer, etc.... all things related to rental contracts, and nothing related to the behavior of vehicles, engines, wheels or houses.
I repeat, I don't mean to be rude, maybe you did it that way for educational purposes, but I think it's a bad example
I don't think you watched the whole example. I was demonstrating how doing inheritance incorrectly and forcing the relationship can lead you into a corner. That's why I redid the inheritance and interface structure at the end to properly set up a flexible structure that is workable well into the future.
@@IAmTimCorey Thanks for answering. Yes, I watched the whole example. Anything done incorrectly can lead you into a corner, and that was the case in the inheritance example. You would had never reached that corner if you had assigned properly responsibilities to each class, that's all I'm saying. There are another examples where inheritance can't give you a good solution and interfaces can, but I think this is not the case. An example with LandVehicles, WaterVehicles and AirVehicles, some of them implementing IEngineVehicle (Car, Motorboat, Airplane) and some of them don't (Bicycle, Sailboat, Glider), would have been a better example. It's just my humble opinion, I don't want to create a discussion. Cheers
Im just hoping C# have a feature like build a bear object
I am not sure what you mean.
@@IAmTimCorey class is weird, it gets complicated real fast.