News:

So the widespread use of emojis these days kinda makes forum smileys pointless, yeah?

Main Menu

[Java] Efficiency/best practice dilemna

Started by Chavo, July 24, 2006, 12:03:47 PM

Previous topic - Next topic

0 Members and 3 Guests are viewing this topic.

Chavo

The code in question is kinda in-between a couple versions I am playing around with, so I won't bother posting all of it since it won't help ;)

I have a class called EventManager which basically receives a generic Event, iterates through a list of EventHandlers for that specific Event and calls a dispath() method on each of those Handlers.

dispatch utilizes Reflection in order to call a method by name that wants to handle the raised Event.  Let me know if I've lost you yet ;)

All of the above works fine.  Now for the 'dilemna' (I wouldn't call it a problem, just a matter of deciding which solution is better).

A class that wants to handle a raised event can have any name it wants, but it must accept the type of arguments that dispatch() specifies.  Since there are a number of events, dispatch() calls the handling object's method and passes a generic superclass.  The handling method must then cast to a sub-class if they want to access the sub-class data.  I find this less than pretty and somewhat error prone.

The alternative is to write seperate dispatch() methods for every single Event type (there are a lot) so that the parent class does not have to be the argument.  This makes it safer/easier for the handling methods, but significantly sloppier looking with all the dispatch methods (and very redundant code).

There is a third option.  One dispatch method could be written accepting the parent class.  The dispatch method could then switch on the type of event and call the handling event with the proper child class.  The problem I see with this approach is that you are switching and casting multiple times for the same object because dispatch will be called multiple times for a single event if there are multiple handlers for that event.

Thoughts?  Am I being too vague?

iago

You could define some standard form, for example:
dispatch(int code, String data);

Then, to accept the differences for other definitions, add an array of objects to the end:
dispatch(int code, String data, Object []vars);

That's like using a variable number of arguments in C, people can do:
dispatch(1, "hi", new Cattle(), null);
And the last two parameters will end up in the object array.  IIRC. 

That's Java's answer to printf() and other variable-parameter functions. 

Incidentally, this may not be the best answer, and I believe it's new in Java 1.5. 

Chavo

I don't see how that helps, or maybe I'm not completely getting it.  It looks very similar to the params functionality of C# which I am very familar with.

Maybe I should explain more about how I am using reflection.

This is my EventHandler class:

import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;

import events.*;

public class EventHandler {

private Object obj;
private Method method;

public EventHandler(Object obj, String methodName)
{
this.obj = obj;
try{
method = obj.getClass().getMethod(methodName,new Class[] {ParentEvent.class});
} catch (Exception e) {
e.printStackTrace(System.out);
}
}

public void dispatch(BNetEvent event) {

try{
method.invoke(obj, new Object[] {event});
}catch(IllegalAccessException iae) {
iae.printStackTrace();
}
catch(InvocationTargetException ite) {
ite.printStackTrace();
}
}

public boolean equals(Object o)
{
try{
EventHandler compare = (EventHandler)o;
if(this.obj.getClass().getCanonicalName().equalsIgnoreCase(compare.obj.getClass().getCanonicalName())
&& this.method.getName().equalsIgnoreCase(compare.method.getName()))
return true;
}
catch(Exception e) {}

return false;
}
}


I create an instance of EventHandler for every event that I want to handle.  I pass the constructor a reference to the object and method name where I want to write the code to handle this event.  When dispatch is called, I use the Method.invoke() method (Method belongs to java.lang.reflection) to call the handling code with a generic object[] for arguments. The limitation on those arguments is in the actual Method constructor.

Chavo

#3
gahh, DUH!

Quotepublic EventHandler(Object obj, String methodName, Class classType)
   {
      this.obj = obj;
      try{
         method = obj.getClass().getMethod(methodName,new Class[] {classType});
      } catch (Exception e) {
         e.printStackTrace(System.out);
      }
   }

determine the class to use in the constructor!  Now to add better error handling if someone trys to use the wrong class.  Superclasses will work without erros though I think, yay.

Joe

Seriously, what is with iago and Cattle? :p
Quote from: Camel on June 09, 2009, 04:12:23 PMI'd personally do as Joe suggests

Quote from: AntiVirus on October 19, 2010, 02:36:52 PM
You might be right about that, Joe.


iago

Quote from: Joex86] link=topic=6821.msg84177#msg84177 date=1153802533]
Seriously, what is with iago and Cattle? :p
Long story

MyndFyre

If you don't mind my saying so, rather than using type reflection which is typically slow, it would probably be better to use an interface or series of interfaces.  I can't imagine that dynamic method invocation the way you have it designed is much different than the way .NET is:



You're using what looks to be the equivalent of MethodBase.Invoke. 

Of course, all of this could be handled with delegates, and still be type-safe, but since Java sucks...  :P
Quote from: Joe on January 23, 2011, 11:47:54 PM
I have a programming folder, and I have nothing of value there

Running with Code has a new home!

Quote from: Rule on May 26, 2009, 02:02:12 PMOur species really annoys me.

iago

Incidentally, on that graph, the call is probably .00001seconds, or less, which would make the invoke like .00001seconds, which is still nothing. 

When it comes to making a decision between programming and speed, choose programming.  With modern computers, a small speed difference rarely matters. 

Chavo

Aye, I looked into it before writing any code at all.  The time difference is negligible since invoke won't be called enough for the difference to be perceivable by a human.  I choose reflection over interfaces for greater power when handling events.

Incidently, I am a big fan of C# and have already written something that does much of this using delegates.  However, this particular program I intend on running from my server which is running debian.  I don't know enough about Mono to know whether I could write the entire program in C# and have it work perfectly so this is easier :)

MyndFyre

Quote from: iago on July 25, 2006, 01:13:21 PM
Incidentally, on that graph, the call is probably .00001seconds, or less, which would make the invoke like .00001seconds, which is still nothing. 

When it comes to making a decision between programming and speed, choose programming.  With modern computers, a small speed difference rarely matters. 
Excuse me?  Invocation through RMI and Reflection could hardly be called a tradeoff between "programming and speed," it's more like a tradeoff of "programming and speed against convenience."

Using Reflection (which is intended to provide information) to call code is like running code in the data segment.  It might not be safe, it shouldn't be practiced, and it goes against the paradigm of the programming language you're using (Java is object-oriented; using Reflection is going against the "black-box" theory).

I'm not saying it's the wrong way to go about this, I'm just saying that calling this "programming" in a tradeoff of "programming and speed" is sorely inaccurate.
Quote from: Joe on January 23, 2011, 11:47:54 PM
I have a programming folder, and I have nothing of value there

Running with Code has a new home!

Quote from: Rule on May 26, 2009, 02:02:12 PMOur species really annoys me.

iago

Quote from: MyndFyrex86] link=topic=6821.msg84307#msg84307 date=1153866947]
Excuse me?
Why does everybody assume they'll be excused?  What if I choose not to allow somebody to be excused for, say, farting?  Do I get to kick them out of my house or something?  But anyways...

Quote from: MyndFyrex86] link=topic=6821.msg84307#msg84307 date=1153866947]
Invocation through RMI and Reflection could hardly be called a tradeoff between "programming and speed," it's more like a tradeoff of "programming and speed against convenience."

Using Reflection (which is intended to provide information) to call code is like running code in the data segment.  It might not be safe, it shouldn't be practiced, and it goes against the paradigm of the programming language you're using (Java is object-oriented; using Reflection is going against the "black-box" theory).

I'm not saying it's the wrong way to go about this, I'm just saying that calling this "programming" in a tradeoff of "programming and speed" is sorely inaccurate.
I'm not sure why you're talking about RMI.  So I'll just ignore that for now, and assume we're talking about local code. 

I've never used the Reflection class before, so I didn't know what it was for.  Your post seemed to be warning him not to use it because of the speed difference.  I mean, why else would you give him a graph of the speeds?  So I was using a common line (especially useful considering the title of this thread), that you're better off with cleaner code than with faster code in almost all cases.  That's all I meant, it's a generic sentiment. 

MyndFyre

Quote from: iago on July 25, 2006, 08:02:22 PM
I'm not sure why you're talking about RMI.  So I'll just ignore that for now, and assume we're talking about local code. 
The "R" was meant for Runtime, not Remote.  Sorry.  In the context of reflection, for me, RMI means the way the execution environment invokes methods, that's all.
Quote from: iago on July 25, 2006, 08:02:22 PM
I've never used the Reflection class before, so I didn't know what it was for.  Your post seemed to be warning him not to use it because of the speed difference.  I mean, why else would you give him a graph of the speeds?  So I was using a common line (especially useful considering the title of this thread), that you're better off with cleaner code than with faster code in almost all cases.  That's all I meant, it's a generic sentiment. 
Well, he initially wanted information about efficiency.  I posted a graph indicating why it was a better practice *and* more speed-efficient to use interfaces rather than dynamic method invocation.  You seemed to think that it was a tradeoff between good programming practice and speed; I was saying it was not.
Quote from: Joe on January 23, 2011, 11:47:54 PM
I have a programming folder, and I have nothing of value there

Running with Code has a new home!

Quote from: Rule on May 26, 2009, 02:02:12 PMOur species really annoys me.