Win a copy of The Java Performance Companion this week in the Performance forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

downcasting in implementation

 
Mohit Sinha
Ranch Hand
Posts: 125
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi All,

I want to understand if it is a good or common practice to use downcasting in the implementation. I have a Type class which has some common behavior. Then we have flavors of this Type class. For brevity sake I will address them as Light, Medium and Heavy.
Light apart from inheriting the derived implementation will also have some custom behavior specific to Light. The same holds true for Medium and Heavy.

We have exposed the generic "Type" as an input parameter. Now the invoking program can pass Light , Medium or Heavy wrapped inside "Type" object reference. (Type t = new Light())
To invoke the specific custom implementation as mentioned above I will have to downcast the Type object reference (Light l = (Light)t)
Is this a common practice to use.

Regards,




 
Ilja Preuss
author
Sheriff
Posts: 14112
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It is sometimes the best you can do, but most often it's better to make use of polymorphism.

How will you know what type to cast to?
 
Mohit Sinha
Ranch Hand
Posts: 125
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
---------------------------------------------
How will you know what type to cast to?
---------------------------------------------
based on the instanceOf operator output we plan to take appropriate action.




 
Ilja Preuss
author
Sheriff
Posts: 14112
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, so that's a bigger concern. This is typically called a "type case", and by many regarded a code smell.

The problem is that it makes the code more rigid by violating the Single Choice Principle - every time you add another type to the code base, you will potentially need to touch any such type case to add the additional type. This makes changes very laboursome and prone to bugs.

The typical solution is to use polymorphism instead. Can you tell us more about how the implementations for the different types would differ? Perhaps with an example?
 
Mohit Sinha
Ranch Hand
Posts: 125
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok. To give the scenario we have is the parent (Type class) has all generic behavior for all possible product types.
Per the design each of these product types have specific instance variables.
so accordingly Light will have specific variables (spInd, fdInd) and it will have methods operating on these variables.
Now Medium type has its own set of such specific variables which make no sense to type:Light.

There is businessProcessor class where all further calculations take place. To make the object model strictly representing the real world business objects we kind of arrived at this structure. Now in the businessProcessor class it becomes inevitable for us to decipher what is the sub type (light,medium or heavy) so we grab all the appropriate input passed along via the Type object.

Thanks!


 
Ilja Preuss
author
Sheriff
Posts: 14112
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Mohit Sinha wrote:
There is businessProcessor class where all further calculations take place. To make the object model strictly representing the real world business objects we kind of arrived at this structure. Now in the businessProcessor class it becomes inevitable for us to decipher what is the sub type (light,medium or heavy) so we grab all the appropriate input passed along via the Type object.


The simplest *object oriented* solution to your problem would be to move the parts of the calculations that are specific to the different types into the Type objects. http://www.pragprog.com/articles/tell-dont-ask

What would happen if you did that?
 
Mohit Sinha
Ranch Hand
Posts: 125
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks Ilja. Your point is well taken.

But this brings another question in my mind. Aren't child objects in an inheritance free to have their own specific methods. The knowledge of these new implementations will never be known parent and will throw an error when trying to access new methods of the child object via a parent object reference.
Are you saying child classes should only stick to overriding and not have new methods.

Is downcasting something to be avoided all the time. How can a downcasting scenario be handled differently.
 
Ilja Preuss
author
Sheriff
Posts: 14112
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Mohit Sinha wrote:
But this brings another question in my mind. Aren't child objects in an inheritance free to have their own specific methods. The knowledge of these new implementations will never be known parent and will throw an error when trying to access new methods of the child object via a parent object reference.
Are you saying child classes should only stick to overriding and not have new methods.


No, I'm not saying that. Sometimes you actually *do* have a reference to the actual type (instead of the parent type), in which case calling methods specific to the single implementation is no problem at all.


Is downcasting something to be avoided all the time. How can a downcasting scenario be handled differently.


In fact, it's not downcasting that's the problem. It's the type check that may come before it. Especially if you have many of them.

The main question you should ask yourself is: "what would happen if I introduced another subtype?" If the answer is "I would have to check for that type and introduce another down cast", look for another solution. One that doesn't violate the Open Closed Principle. That solution will likely make use of some form of polymorphism.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic