2

So I want to implements the Chain of Responsibility but use generics, with an upper bound.

public abstract class Handler<C extends Command> {

    private Handler<? extends Command> successor;

    public Handler(Handler<? extends Command> successor) {
        this.successor = successor;
    }

    public final String handle(C cmd) {
        if (canHandle(cmd)) {
            return doHandle(cmd);
        } else {
            // The method doHandle(capture#3-of ? extends Command) in the type Handler<capture#3-of ? extends Command>
            // is not applicable for the arguments (C)
            return successor.doHandle(cmd);
        }
    }

    protected abstract boolean canHandle(C cmd);

    protected abstract String doHandle(C cmd);

}

abstract class Command {
    public String getParamBase() {
        return "base";
    }
}

class CommandTypeOne extends Command {
    public String getTypeOneParam() {
        return "ParamTypeOne";
    }
}

class CommandTypeTwo extends Command {
    public String getTypeTwoParam() {
        return "ParamTypeTwo";
    }
}

Sure I could have the class non-generic, and have Command as parameter everywhere, and that would work. But I don't want to use casting in the doHandle method to pass to the corresponding subtype of Command. I want to have a Handler for each of the subtypes, generic, and just chain them.

The issue I get is: The method doHandle(capture#3-of ? extends Command) in the type Handler is not applicable for the arguments (C)

Why if C extends Command?

dalvarezmartinez1
  • 1,385
  • 1
  • 17
  • 26
  • At which line you have the error? – gurghet Apr 16 '15 at 19:08
  • Do you need to use generics in this case? All objects that extend `Command` have an is-a relationship to `Command`. Will your `Handler` be expecting all `Commands` to be of the same sub-type? – PaulProgrammer Apr 16 '15 at 19:08
  • Related question: http://stackoverflow.com/questions/1684121/generics-error-not-applicable-for-the-arguments – Mick Mnemonic Apr 16 '15 at 19:11
  • @gurghet you can see the error in the code too, I put it there as a comment also. PaulProgrammer that is the thing, the handlers are not of the same subtype, I want to have one handler for each subtype, the subtype will be passed as generic. I want to use generic to avoid using instanceof and casting. Thanks for the link Mick will read it. – dalvarezmartinez1 Apr 16 '15 at 19:28

3 Answers3

1

Imagine what would happen if you replaced Command by Animal (superclass of Cat and Dog).

The signature of the successor reference says it can handle some type of Animal, say only Cats. On the other hand, the cmd parameter of the handle() method also says that the command to handle can be of any other subtype of Animal - here, Dog could be a valid type.

You see that nothing guarantees that the successor handler will be able to manage the particular type of command, so the compiler gets somewhat angry.

Olivier Croisier
  • 6,139
  • 25
  • 34
  • Handler successor = new Handler(null); Handler dogHandler = new Handler(successor); The method canHandle, doHandle, handle in DogHandler handles Dog The method canHandle, doHandle, handle in successor handles Cat Not sure I follow. – dalvarezmartinez1 Apr 16 '15 at 19:47
  • If your instance is declarede as a `Handler`, the type variable `C` will be `Dog` in the signature of the `handle()` method. But if its `successor` field is of type `Handler`, you have a problem.` – Olivier Croisier Apr 16 '15 at 19:52
  • yes but why, they are both Animal. I don't see that much difference between extends Command> and – dalvarezmartinez1 Apr 16 '15 at 19:53
  • Because your type signatures don't say "I can handle any Animal", they say "I can handle only one type of animal", and the precise type of animal declared by `Handler` can be different from that of its successor. – Olivier Croisier Apr 16 '15 at 19:56
1

Your field successor could hold an instance which is really a Handler<CommandTypeOne> because it can hold everything as long as C extends Command. The signature of its doHandle method would be String doHandle(CommandTypeOne cmd). If you then call successor.doHandle() in handle() you would pass a parameter that is only guaranteed to be a Command but not a CommandTypeOne.

Maybe you should have a look into PECS. Producer extends - Consumer super. You can google it. In your case your doHandle method is a consumer and you should use super instead of extends.

I would probably go without a generic in this case. Put Command where C is now. This allows to pass Commands and Subtypes to a handler chain. To allow a handler to distinguish commands you could establish an id for commands possibly with a String or int. Or you could use instanceof to allow a handler to check for a specific subtype of command. Both solutions are not very object oriented.

At this point your Command feels like a data container with different content depending on your subtype.

Community
  • 1
  • 1
Robert Kühne
  • 898
  • 1
  • 12
  • 33
  • flex my PECS? I've heard about it some time ago already forgot will try to look into it. – dalvarezmartinez1 Apr 16 '15 at 19:30
  • I think you're saying a similar thing to what Olivier Croisier is saying, and I do understand your explanation perfectly. But after reading a bit about PECS I don't see how should I modify the code properly. Even if I make the error dissapear, a Handler is not a subtype of a Handler and I cannot create the handler chain... – dalvarezmartinez1 Apr 16 '15 at 21:46
0

Here your Handler class

//In your case 'C extends Command' in class declaration will be enough 
public abstract class Handler<C extends Command> { 

private Handler<C> successor;

public Handler(Handler<C> successor) {
    this.successor = successor;
}

public final String handle(C cmd) {
    if (canHandle(cmd)) {
        return doHandle(cmd);
    } else {
        // The method doHandle(capture#3-of ? extends Command) in the type Handler<capture#3-of ? extends Command>
        // is not applicable for the arguments (C)
        return successor.doHandle(cmd);
    }
}

protected abstract boolean canHandle(C cmd);

protected abstract String doHandle(C cmd);

}

Yaroslav Kovbas
  • 430
  • 4
  • 7
  • Correct me if I'm wrong byt Isn't this exactly what I'm trying to avoid? Let's say we have one Handler this means it's successor will be of able to handle only according to the constructor and the signature of the successor field. – dalvarezmartinez1 Apr 16 '15 at 19:37
  • Does it make sense to have Handler with successor like Handler? If chain request will be CommandTypeOne it should be handled by successor of type Handler only, isn't it? Or i don't understand clearly what do you actually want to do. – Yaroslav Kovbas Apr 16 '15 at 20:02
  • Each handler should handle a subtype. Try creating a class HandlerTypeOne extends Handler {......} now look at it's constructor. It accepts Hander like you say it doesn't make sense to have 2 handlers handle the same type of request. – dalvarezmartinez1 Apr 16 '15 at 20:32
  • Oh, i finally got your point, and that what you gonna do is not possible using java jenerics. – Yaroslav Kovbas Apr 16 '15 at 21:37
  • I think I've realized just that, answering to Sponiro's answer. Thank you very much for your time sir. – dalvarezmartinez1 Apr 16 '15 at 21:59