Summary
This episode continues the discussion on practical object-oriented programming, focusing on polymorphism. The host talks about the importance of flexibility in design and how polymorphism allows for hooks to be added to classes for future extension.
Detailed Notes
Polymorphism in object-oriented design refers to the ability of an object to take on multiple forms. This allows for flexibility in design and enables the addition of hooks to classes for future extension. The host discusses the importance of polymorphism and how it can be used to improve the usefulness and user experience of classes. The challenge for the week is to identify areas where polymorphism can be stretched and improved. The developer should communicate clearly with the user through parameters and clear form of communication. The episode continues the discussion on practical object-oriented programming, focusing on polymorphism.
Highlights
- Flexibility is key in object-oriented design.
- Polymorphism allows for hooks to be added to classes for future extension.
- Parameterization is a clean way to handle polymorphic behavior.
- The challenge for the week is to identify areas where polymorphism can be stretched and improved.
- The developer should communicate clearly with the user through parameters and clear form of communication.
Key Takeaways
- Polymorphism is a key concept in object-oriented design.
- Polymorphism allows for flexibility and hooks to be added to classes for future extension.
- Parameterization is a clean way to handle polymorphic behavior.
- The challenge for the week is to identify areas where polymorphism can be stretched and improved.
- The developer should communicate clearly with the user through parameters and clear form of communication.
Practical Lessons
- Use polymorphism to add hooks to classes for future extension.
- Communicate clearly with the user through parameters and clear form of communication.
- Parameterize polymorphic behavior for clean and maintainable code.
Strong Lines
- Flexibility is key in object-oriented design.
- Polymorphism allows for hooks to be added to classes for future extension.
- Parameterization is a clean way to handle polymorphic behavior.
Blog Post Angles
- The benefits of polymorphism in object-oriented design.
- How to use polymorphism to add hooks to classes for future extension.
- The importance of clear communication with the user through parameters and clear form of communication.
- The use of parameterization to handle polymorphic behavior.
Keywords
- polymorphism
- object-oriented design
- flexibility
- hooks
- parameterization
Transcript Text
This is Building Better Developers, the Develop-a-newer podcast. We will accomplish our goals through sharing experience, improving tech skills, increasing business knowledge, and embracing life. Let's dive into the next episode. Well, hello and welcome back. We're continuing our season where we're looking at practical object-oriented programming. In this episode, we're going to continue looking into polymorphism. I'm going to talk a little bit about some practical ways to stay consistent, but also to allow for flexibility. Flexibility is key in object-oriented design. This actually is something that should be on your mind on a regular basis, really as you're designing, then definitely as you're implementing. In general, it comes down to, is this thing that we're building always going to act in a certain way, or are there hooks that we need to have available for it? An example would be, is the ID for this class, the primary key for the instances of this, let's just say are they always going to be integers, or is it potentially that they're going to be global unique IDs? Something like that. For the print that we talked about in the prior episode, is print always going to be to screen, or are there maybe some other ways we need to look at? The other ways we should look at is something that I want to talk about here as some practical approaches to maybe to leave some hooks in so we can extend and build on our solution as we get further into either children classes, or if it's something that we know we need a general approach to something, but then there might also be some specialized ones per class as we go with across classes instead of up and down within a hierarchy. Yet, we still want to have some sort of consistency to it, and even something that we could potentially throw into a collection and essentially run that thing across all of the classes. The easiest way to do this is to parameterize it, is to have a parameter that you send in that is some sort of indicator basically of what you want to do. For print, this would be commonly is that you maybe have a, and it probably would be some sort of an enumerated value that would basically be print, and it's the format or target to be, maybe you send it XML or CSV or who knows, could be binary or something like that. There's different ways that you can do it. What you would do is you want to make sure that that is some sort of an enumerated type is handled at the root, or maybe there's a helper class. And then you can add to that later on. You can always, with part of an extension, is maybe an extended class would allow for another enumerated type. Now, when you do something like that, you're going to want to do one, some sort of validation so that if the type doesn't exist for a given class, then it just spits out some sort of an error or an exception or something that is consistent. Or maybe I guess you could just send back like in the case of a print, something empty, but that's probably not what you want to do. You want to have some sort of an error code or something that somebody can check to ensure that that comes out correctly, which can complicate things like a print. Although I guess print to screen, normally if you call that, then that you would just have a, you wouldn't necessarily have a return value. You would just have a success value or something like that. But if you did something like to string, then you would need to have some sort of, probably have an exception mechanism. So the to string would work. You would pass it in the parameters. Normally it would send back a string, but if the parameter you send is not valid, that would have to have its own exception and deal with it in that route. And that's a very plausible way to do it. And actually it's a very clean way because what you can do is you can, and this sort goes to another thing, is you have some sort of a default at the route or even if this is across a lot of different classes. So for example, when we talked about the print, actually the to string, I guess it was, in Java, for example, it will kick out the class and the pointer number, or basically it's the class name and the pointer address. That's the default. If you don't override it, then you get that. You could do the same sort of thing with a value, which I guess you could do that instead of an exception. As you would either, if somebody sends a specific ID or type and the class supports it, then it'll kick it out that way. If not, then it kicks it out in whatever the default is. So this could be an extension kind of thing, but because it's a very different way to handle that polymorphic behavior, it makes more sense that it's some sort of a parameter so that it's clear to the user that you're sending this with the signature that you're telling it to do something slightly different from what the norm is. So this is where you would actually be able to sort of group functionality via some sort of polymorphic behavior. Another example you might see a lot would be a save. And typically maybe this is saved to database, but potentially you would pass in maybe a database name or a type of some sort like development test, QA stage, production, something like that, so that you would have essentially the same calls, but you would send in a, for an instance, you would send something in that would send it somewhere else. You could see this database save. A good example of this would be if you have some way, some sort of a distributed data store and maybe you have to tell it which node that data lives on or something along those lines. So you would pass that in and be able to, and that would actually have a slightly different I guess logical path within the, whatever that method is or function. And so we can build these hooks in and we should be doing that as part of our design as we're thinking through this stuff is think about it. Is this something that's always going to be this way? And if not, then how do I handle that? As we mentioned a little bit in the prior one, we can do that through naming is we can have specific naming and keep simpler signatures essentially. So less parameters, but more meaningful names and more methods when all is said and done. Or we can try to group stuff together in a way that we pass a value in and it allows us to specialize based on that. If you do the pass in a parameter approach, then that does allow you to do things like have a lowest common denominator fairly easily. For example, print to XML, but if it doesn't print to XML, then it's going to print some sort of a very simple string or something like that. Could be a problem because I mean, you've got to consider like, for example, XML, you would want it to not kick something out that is improperly formatted, you know, XML. But you could easily do this where in XML in particular, where you have something where maybe you pass parameter and there are certain sections, certain things that are printed or not, depending on what the data is. So maybe you have this is a great one to use for the example like debugging is that you send a flag in an enumerated type of some sort that says I'm going to do this for a debugger for informational only if there's errors and things like that. When you do logging and debugging, you'll see that a lot where you'll see these different error levels and see some classes that handle those accordingly, which again means what you can do is eventually extend those and add new types somewhere down the line that are supported. They just wouldn't be supported in either earlier versions or things that are further up the hierarchy or I guess maybe even potentially further down the hierarchy. And there may be some point where you block it, where you block certain types and say, no, I'm not going to provide this. This can also be used for a lot of, there's a lot of different ways to do stuff like this. The key here is that you've got the same signature all the way through and within the parameters there are switches essentially that the, you know, they're flag settings that users can use so that is very, their intent is clear and therefore their expectations should be very clear. Print itself, we've already mentioned can be very vague, but if you add a parameter print that is essentially some sort of an output or a target or something like that, then suddenly it really clarifies a print. If you have another parameter that's a format, you know, so you have format and target, then it gets very specific very quickly and it allows you to basically open communication with the developers. They can say, this is what I want. And you would then be able to either say, yes, I can do that. Here it is. Or no, I can't. It's an exception, you know, or an error or something along those lines. So don't be afraid to put hooks in like that. Sometimes it is just a parameter that maybe that you allow it to be null if that's possible or have some sort of a default or a null or zero or something that you can send in that you do handle at the most root level within the hierarchy or in, you know, that everything that implements this must implement it this way, which is perfect for an interface, which we haven't talked about yet, but when we get into interfaces, that's a perfect use of that is where you say, OK, if you're going to use this, this is what it needs to look like. And then, you know, the user, the developer that extends on that or makes use of that needs to make sure they follow the rules, basically. So I think we'll sort of pause here as we're continuing to talk through polymorphism and some practical uses, and we'll pick this up next time around. The challenge for the week for this one is, are there some, are you stretching the boundaries of polymorphism with some of your methods? Would it make more sense to pass some sort of parameter in that allows users to be specific or allows you to distinguish these, I will call them families of functions, you know, these things that are somewhat related but not quite, and maybe a parameter or two would allow you to open a clear form of communication from the developer to you and you back to the developer that uses that so that the whole usefulness and user experience of the classes you're building is improved. That being said, I'll do it this time. So go out there, however you polymorphically look at it, whether you send parameters with it or not. At the end of the day, make sure you do have a good one. Have a great week and we will talk to you next time. Thank you for listening to Building Better Developers, the Developer Noir podcast. For more episodes like this one, you can find us on Apple Podcasts, Stitcher, Amazon, and other podcast venues, or visit our site at developernoir.com. Just a step forward today is still progress, so let's keep moving forward together. One more thing before you go. Developer Noir podcast and site are a labor of love. We enjoy whatever we do trying to help developers become better. But if you've gotten some value out of this and you'd like to help us, be great if you go out to developernoir.com slash donate and donate whatever feels good for you. If you get a lot of value, a lot. If you don't get a lot of value, even a little would be awesome. In any case, we will thank you and maybe I'll make you feel just a little bit warmer as well. Now you can go back and have yourself a great day.