I am building an AI for an RTS game. (For the Spring RTS engine, if anyone is interested.) The way I have set it up it consists mainly of a collection of Components that communicate by means of fired Events. Every component has a method handleEvent(Event) that receives events fired by the other components.
Event is an interface. A hierarchy exists, each subclass providing more detailed information on the the event they represent, which can be accessed by using the getter methods specific to that class. As an example, the class UnitGainedEvent implements the Event interface. This class has a subclass UnitFinishedEvent (which indicates construction of a unit or building is completed, for anyone that is curious.)
Not every component will be interested in all events, so I would like to let Components simply pick the events they are interested in and receive only those. Also, the set of possible events is extendable, so it is not a valid option to let Components have designated methods for each Event type. Initially I thought the visitor pattern might help me with this problem, but it fails because it also requires a fixed set of Event types. (I'm not 100% sure I understand the pattern correctly. Please do correct me if I'm wrong.)
So far, the only solution I have found is to implement each Component's handleEvent(Event) method something like this:
public int handleEvent(Event event)
{
if (event instanceof UnitGainedEvent)
{
UnitGainedEvent unitGainedEvent = (UnitGainedEvent) event;
// things to do if I lost a unit
}
else if (event instanceof UnitLostEvent)
{
UnitLostEvent unitLostEvent = (UnitLostEvent) event;
// things to do if I lost a unit
}
// etc.
}
However, I don't really like having to cast the events to the specific Event classes. Now, remembering that method overloading can be used to invoke different methods depending on the runtime type of a parameter, I quickly came up with a brilliant solution, elegant as it was simple: I could create a base class with an empty implementation of handleEvent(Event), and simply have subclasses receive the events they are interested in by creating a method handleEvent(UnitGainedEvent unitGainedEvent), for example. Wanting to make sure it would work I set up a quick test case:
public class Main
{
public static void main(String[] args)
{
handleEvent(new UnitGainedEvent(null));
}
public static void handleEvent(Event event)
{
System.out.println("Handling generic Event");
}
public static void handleEvent(UnitGainedEvent event)
{
System.out.println("Handling UnitGainedEvent");
}
}
And to my great satisfaction, this code actually prints 'Handling UnitGainedEvent.' So I set about implementing.
My Component base class looks like this: (Well, not really. This is the Component class stripped of everything not relevant to the problem I'd like to demonstrate.)
public class Component
{
public void handleEvent(Event event)
{
System.out.println("Handling Event");
}
}
And this is an example of a subclass:
public class SomeComponent extends Component
{
public void handleEvent(UnitGainedEvent unitGainedEvent)
{
System.out.println("Handling UnitGainedEvent");
}
}
In order to test the setup, I use the following main class:
public class Main
{
public static void main(String[] args)
{
Component component = new SomeComponent();
component.handleEvent(new UnitGainedEvent(null));
}
}
So I run the code, and to my great surprise, the result is a neatly printed 'Handling Event.' Interestingly enough, if I change the type of the component variable to SomeComponent, it does print 'Handling UnitGainedEvent.' For some reason or another, the system blindly invokes the Component class' handleEvent(Event) method, instead if the overloading SomeComponent's handleEvent(UnitGainedEvent). (I would be interested in hearing Sun's reasoning behind this, thought it isn't really relevant to my question - not like they'll fix it just because a handful of people would find it a very useful feature.)
Scouring the net tells me that other people have run into the same problem. Very few people, from the minute amount of information I find, but people nonetheless, although I find more information on general method overloading and overriding than I ever wanted to know. However, in the end, I fail to find a solution.
Now, my (fairly obvious) question is, is there some way to get around this problem? Failing that, can anyone think of, or help me find, another solution that is equally convenient?
Edit: I can hardly believe I have answers after only ten minutes. I'm pleasantly surprised. :) However, most of the answers so far suggest in one form or another that I make one seperate method for each possible Event type. Technically this is possible, but this would require me to go back into the code and add a new method every time someone comes up with a new Event type. Which I've learned is bad coding practice. (Plus, I already have some 20+ Event types, and I'm not even done yet.) Instead, I would rather do use the solution involving casting, as described above. At least that way I can assure that unknown event types are simply ignored, leaving me free to only handle those events where I want to use them. I'm really hoping for a solution that combines the best of both however. No casting, and no going back into my code for each event type.
Many thanks in advance, Loid Thanead