I've recently began the construction of a class, the mechanics of which have lead me to the conclusion that I don't know my way around polymorphism 100%.
Here's what I'm doing: The class contains a function which deals with a 'Targetable' argument - where 'Targetable' is an interface. The function then must deal with this 'Targetable' object differently depending upon whether this object is in actuality an Item object, a Player object, a Room object, or anything else that implements Targetable. A great many classes do.
What are my options here? So far I've come up with the following ideas, some of which I think belie my misunderstanding of polymorphism:
A) Function takes the argument as Object, then goes through a series of if(object.getClass().equals("Item")) statements.
B) Function takes the argument as Targetable, and Targetable has a kind of identifyYourself() function which all 'Targetable classes' have to implement, revealing their actual class.
Both seem a bit clunky to me at first glance. The idea that an object has to have an identifyYourself() function solely for the purpose of some coding minutiae seems unintuitive.
Specifics aside, my question is actually a general one: How does one take advantage of polymorphism by passing more abstract objects, possibly even passing Object itself, and still be able to recognize that object A needs to be dealt with slightly different than object B?
They are, after all, entirely different things which just happen to both be targetable by the player.
The beauty of polymorphism is that you shouldn't have to use either method you listed. Abstractly, you write a class with generic methods. Then you extend that class with a more specific class, and override the methods you want. The overridden methods must be the same name as the methods in the superclass. Now, take this generic example. Create a class called Animal, which has a makeNoise() method. Create an instance of a Dog, but store it as an Animal. eg. Animal dog = new Dog(); The Dog class extends Animal, and it also contains a makeNoise() method that does something different than Animal's makeNoise() method. Now when you take your object dog and call makeNoise() (dog.makeNoise()) the correct method should be run because of polymorphism. Going back to your problem, basically what needs to happen is that you need to list all your generic methods in the Targetable interface. Then in each of your classes that implement the interface, they need to have all the same methods actually defined. Then all you need to do is create a Targetable object, and call the method you want to run. Let's say your Targetable object happens to really be a Player object. When you call myTargetableObject.getName(), java knows to call the Player class's version of getName(), because it really is a Player object. You don't have to do any extra work. I hope that helps, or at least gets you headed in the right direction. Let us know what progress you make!
Studying for SCJP 6
Joined: May 22, 2008
Thanks for the quick response!
A little more information: The function of which I speak is a part of a Spell object, so my immediate concern is that it's not the Player or Item that's going to perform a function when targeted, it's the Spell object itself. Furthermore, a Spell object should be able to do all sorts of things when one decides to detonate() it, so the option of adding functions to Targetable for every potential spell effect would be an endless task.
Here's my thought on solving the problem: A) Spell.detonate(Targetable target) B) Now, any object that detonate is passed will be Targetable, but only some of them will implement Combative, and only some will be sub-classes of Item, and only some will be of object Room, so..... C) We create the function Targetable.type() and override accordingly.
Finally, an example of a detonate() would then look a bit like this:
public class FlashOfLight extends Spell
public void Detonate(Targetable target) if(target.type().equals("item")); // Add 'bleached by a bright light' to description. if(target.type().equals("room")); // Reveal all hidden objects/exits if(target.type().equals("monster")); // Blind monster, send it into round time
That's my best thinking... can you guys think of a more OOP / intuitive approach? [ December 06, 2008: Message edited by: Alex Birmingham ]
Joined: Jul 11, 2006
Nice thinking. I actually attempted to make a text-based adventure game, and ran into this same problem. I never finished the project, but I would love to find out your solution to this problem, to see a good object oriented design. Have you tried implementing your new approach? When I get time (hopefully a little later today) I will take a look at what I have in my program, and see if I can get something working with your ideas. It would be awesome to find a solution. Also, I can send you what I have if you want.