使用泛型实现责任链

时间:2015-04-16 19:04:46

标签: java generics chain-of-responsibility

所以我想实现责任链,但使用泛型,上限。

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";
    }
}

当然,我可以让这个类非泛型,并且在任何地方都有Command作为参数,这样就行了。但是我不想在doHandle方法中使用强制转换来传递给Command的相应子类型。我希望为每个子类型设置一个处理程序,通用,并将它们链接起来。

我得到的问题是: Handler类型中的方法doHandle(捕获#3-of?extends Command)不适用于参数(C)

为什么C扩展Command?

3 个答案:

答案 0 :(得分:1)

想象一下,如果您将Command替换为AnimalCatDog的超类),会发生什么。

successor引用的签名表示它可以处理某种类型的动物,比如说Cats。另一方面,cmd方法的handle()参数也表示要处理的命令可以是Animal的任何其他子类型 - 这里,Dog可以是有效类型。 / p>

你看,没有什么能保证successor处理程序能够管理特定类型的命令,所以编译器会有点生气。

答案 1 :(得分:1)

您的字段后继者可以拥有一个实际为Handler<CommandTypeOne>的实例,因为它可以保存所有内容C extends Command。其doHandle方法的签名为String doHandle(CommandTypeOne cmd)。如果您随后在successor.doHandle()中拨打handle(),则会传递一个仅保证为Command但不是CommandTypeOne的参数。

也许你应该看看PECS。制片人延伸 - 消费者超级。你可以google它。在您的情况下,您的doHandle方法是消费者,您应该使用super而不是extends。

在这种情况下我可能没有通用。将命令放在C所在的位置。这允许将命令和子类型传递给处理程序链。要允许处理程序区分命令,您可以为可能使用String或int的命令建立id。或者您可以使用instanceof来允许处理程序检查特定的命令子类型。这两种解决方案都不是面向对象的。

此时,您的Command感觉就像一个具有不同内容的数据容器,具体取决于您的子类型。

答案 2 :(得分:0)

这是你的Handler类

//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);

}