I have been told at some stage at university (and have subsequently read in upteen places) that using instanceof
should only be used as a 'last resort'. With this in mind, is anyone able to tell be if the following code I have is a last resort. I have had a look around on stack overflow but cannot quite find a similar scenario - perhaps I have missed it?
private void allocateUITweenManager() {
for(GameObject go:mGameObjects){
if (go instanceof GameGroup) ((GameGroup) go).setUITweenManager(mUITweenManager);
}
}
where
mGameObjects
is an array, only some of which areGameGroup
typeGameGroup
is a subclass of abstract classGameObject
.GameGroup
uses interfaceUITweenable
which has methodsetUITweenManager()
GameObject
does not use interfaceUITweenable
I suppose I could equally (and probably should) replace GameGroup
in my code above with UITweenable
- I would be asking the same question.
Is there another way of doing this that avoids the instanceof
? This code cannot fail, as such (I think, right?), but given the bad press instanceof
seems to get, have I committed some cardinal sin of OOP somewhere along the line that has me using instanceof
here?
Thanks in advance!
The problem with instanceof is that you can suffer from future object hierarchy changes. The better approach is to use Strategy Pattern for the cases where you are likely to use instanceof. Making a solution with instanceof you are falling into a problem Strategy is trying to solve: to many ifs. Some guys have founded a community. Anti-IF Campaign could be a joke but untipattern is serious. In a long term projects maintaining 10-20 levels of if-else-if could be a pain. In your case you'd better make a common interface for all objects of your array and implement
setUITweenManager
for all of them through an interface.EDIT
There are two primary things you can do here to relieve yourself of this specific instance of
instanceof
. (pun?)Do as my initial answer suggested and move the method you are targeting up to the class you are iterating. This isn't ideal in this case, because the method doesn't make sense to the parent object, and would be polluting as Ted has put it.
Shrink the scope of the objects you are iterating to just the objects that are familiar with the target method. I think this is the more ideal approach, but may not be workable in the current form of your code.
Personally, I avoid
instanceof
like the plague, because it makes me feel like I completely missed something, but there are times where it is necessary. If your code is laid out this way, and you have no way to shrink the scope of the objects you are iterating, theninstanceof
will probably work just fine. But this looks like a good opportunity to see how polymorphism can make your code easier to read and maintain in the future.I am leaving the original answer below to maintain the integrity of the comments.
/EDIT
Personally, I don't think this is a good reason to use
instanceof
. It seems to me that you could utilize some polymorphism to accomplish your goal.Have you considered making
setUITweenManager(...)
a method ofGameObject
? Does it make sense to do this?If it does make sense, you could have your default implementation do nothing, and have your
GameGroup
override the method to do what you want it to do. At this point, your code could just look like this then:This is polymorphism in action, but I am not sure it would be the best approach for your current situation. It would make more sense to iterate the
Collection
ofUITweenable
objects instead if possible.It is always a bit "fishy" to me to mix objects of different classes in the same Collection. Would it be possible / make sense to split the single Collection of GameObjects into multiple Collections, one of mere GameObjects, another of UITweenables? (e.g. use a MultiMap keyed by a Class). Then you could go something like:
Now, you still need an
instanceof
when you insert into the map, but it's better encapsulated - hidden from the client code who doesn't need to know those detailsp.s. I'm not a fanatic about all the SW "rules", but Google "Liskov Substitution Principle".
I learned about
Visitor pattern
in Compiler class at university, I think it might apply in your scenario. Consider code below:And then you can put a method in
GameObject
interface like this:And then each
GameObject
implements this method:This is specially useful when you've complex inheritance hierarchy of
GameObject
. For your case your method will look like this:The problem with this approach is that it doesn't usually appear at one place only in your code and thus makes it more or less painful to add another implementations of the interface in the future. Whether to avoid it depends on your consideration. Sometimes YAGNI can be applied an this is the most straightforward way.
Alternatives had been suggested by others, for example the Visitor pattern.
You could use the mGameObjects container for when you need to do something on all game objects and keep a separate container only for GameGroup objects.
This will use some more memory, and when you add/remove objects you have to update both containers, but it shouldn't be a noticeable overhead, and it lets you loop very efficiently through all the objects.