Here is the programmers.stackexchange.com question:
Is it okay to have objects that cast themselves, even if it pollutes the API of their subclasses?
I have a base class,Base
. It has two subclasses,Sub1
andSub2
. Each subclass has some additional methods. For example,Sub1
hasSandwich makeASandwich(Ingredients... ingredients)
, andSub2
hasboolean contactAliens(Frequency onFrequency)
.
Since these methods take different parameters and do entirely different things, they're completely incompatible, and I can't just use polymorphism to solve this problem.
Base
provides most of the functionality, and I have a large collection ofBase
objects. However, allBase
objects are either aSub1
or aSub2
, and sometimes I need to know which they are.
It seems like a bad idea to do the following:
for (Base base : bases) {
if (base instanceof Sub1) {
((Sub1) base).makeASandwich(getRandomIngredients());
// ... etc.
} else { // must be Sub2
((Sub2) base).contactAliens(getFrequency());
// ... etc.
}
}
So I came up with a strategy to avoid this without casting.Base
now has these methods:
boolean isSub1();
Sub1 asSub1();
Sub2 asSub2();
And of course,Sub1
implements these methods as
boolean isSub1() { return true; }
Sub1 asSub1(); { return this; }
Sub2 asSub2(); { throw new IllegalStateException(); }
AndSub2
implements them in the opposite way.
Unfortunately, nowSub1
andSub2
have these methods in their own API. So I can do this, for example, onSub1
.
/** no need to use this if object is known to be Sub1 */
@Deprecated
boolean isSub1() { return true; }
/** no need to use this if object is known to be Sub1 */
@Deprecated
Sub1 asSub1(); { return this; }
/** no need to use this if object is known to be Sub1 */
@Deprecated
Sub2 asSub2(); { throw new IllegalStateException(); }
This way, if the object is known to be only aBase
, these methods are un-deprecated, and can be used to "cast" itself to a different type so I can invoke the subclass's methods on it. This seems elegant to me in a way, but on the other hand, I'm kind of abusing Deprecated annotations as a way to "remove" methods from a class.
Since aSub1
instance really is a Base, it does make sense to use inheritance rather than encapsulation. Is what I'm doing good? Is there a better way to solve this problem?
Tags: java, inheritance, type-casting
asked by codebreaker