<Generics> Is this a good use of Java Generics?! UPDATED: Another question included.

Hi,
I am doing a strange use of generics, and I would like to know from you if is a good use of them or if it's bad.

I wrote this interface:

and this 2 implementing class:

Is this a BAD use of generics?

My aim with this code is to make a polymorphic use of Executor implementing classes, but the problem is that, depending from the Executor implementing class,
they need a specific type parameter, and that's why I am making the 'execute' method generic.

Is this bad ?
I mean, should generic methods be used only for methods that work whatever type 'T' you pass them, or can be used also in this case,
in which each different implementation of "execute(T arg)" method needs a particular Type to work ?

Thanks to all who will help me anwering.

SCJP6 with score 90%. I am conscious of my ignorance and ready to learn from everyone.

Think about what you're asking for. It sounds like you want compile-time type checking of a method, the type signature of which is unknown until runtime!

I think you may need to consider how to define IRecover without generics, so that the argument type(s) of recover() are sufficient for all implementations to work with. If you want to dynamically look up an implementation, then it has to be polymorphic!

Emanuele Ghe
Ranch Hand

Joined: Feb 04, 2009
Posts: 111

posted Feb 06, 2009 05:20:16

0

Ernest Friedman-Hill wrote:Think about what you're asking for. It sounds like you want compile-time type checking of a method, the type signature of which is unknown until runtime!

I think you may need to consider how to define IRecover without generics, so that the argument type(s) of recover() are sufficient for all implementations to work with. If you want to dynamically look up an implementation, then it has to be polymorphic!

Well, actually "Googling" I've found someone that did what I mean, and actually I am studying his article to deeply understand and use his solution.

I've read over that article twice, now, and I can't figure out what this gets you; it's seems to me it's really just an insanely complex way to emulate non-polymorphic method calls! The strength of the Command pattern is being able to bundle up many individual Commands and put them in a queue, or hand them to a Thread pool for execution, or pass them down a chain of command. As soon as you do any of these things with the "commands" described in that article, the information about the return type disappears -- you can't have a Queue<Command> which lets you recover that return type information -- and of course, that Queue would want to call those commands polymorphically, and in doing so, it wouldn't be prepared to handle the different return types anyway.

Everything in that article is statically bound: you need to know the class name, argument types, and return type of a Command to be able to use it. That means that the code can't make any use of new Commands discovered or loaded at runtime -- another traditional strength of the Command Pattern. The application can only use the commands that are hard-wired into it.

So quoting the final code from his article, I cannot for the life of me figure out why this:

I've read over that article twice, now, and I can't figure out what this gets you; it's seems to me it's really just an insanely complex way to emulate non-polymorphic method calls! The strength of the Command pattern is being able to bundle up many individual Commands and put them in a queue, or hand them to a Thread pool for execution, or pass them down a chain of command. As soon as you do any of these things with the "commands" described in that article, the information about the return type disappears -- you can't have a Queue<Command> which lets you recover that return type information -- and of course, that Queue would want to call those commands polymorphically, and in doing so, it wouldn't be prepared to handle the different return types anyway.

Everything in that article is statically bound: you need to know the class name, argument types, and return type of a Command to be able to use it. That means that the code can't make any use of new Commands discovered or loaded at runtime -- another traditional strength of the Command Pattern. The application can only use the commands that are hard-wired into it.

So quoting the final code from his article, I cannot for the life of me figure out why this:

is supposed to be any better than, say, something like this:

Well, in fact what I am trying to do is to solve a problem without doing stupid "if-chaining" code, trying to use some good object oriented design to get higher quality code.

The problem is:

As "input", I have a pameter that can take, for example, at least 3 valuses, say:

For each "input" value, there is a logic class that handles the logic behind the "input":

Even if each "doLogic" method has parameters depending from the "Input", the operations that they do are "the same" (not strictly the same from the point of view of code, but logically the same, for example "save something":
it could be that "ALogic" saves something to a disk referred by "args", the "BLogic" saves something else to a remote storage, and the BParameters are the IP/PORT of the remote storage, etc etc).

A simple way to implement this behaviour could be:

I don't like this, because in my opinion this has low quality: if you want to add a 4th option, you have to add another if block etc etc.

I wanna do something modular, that dynamically loads the requested logic class based on the input, and executes it. And the code I wanna write must be easily "upgradable" without having to add an if etc etc, but only adding the "logic class" and, for example, the new Input value to an enum.

For example something like:

In this way, adding a new input value is simple as adding a new value to the enum and providing the new logic class, without touching all the rest.

The problem is that, as you may have noticed the "doLogic" method here DOES NOT TAKE INPUT PARAMETERS.

What I was trying to solve is implementing this structure having "doLogic" method that takes different parameters based on the input value, continuing to hide the implementation with the interface, and that's why I used your suggestion:

But, in this way, I am not able to get safe-type checking at compile time when invoking the "doLogic(T arg)" from client classes, letting the client pass the wrong arguments and making a nice RuntimeExeption bubble up...And this makes the use of generic quite "useless", doesn't it ?