【发布时间】:2014-05-19 06:44:54
【问题描述】:
我正在编写一个流畅的 API 来配置和实例化一系列“消息”对象。我有一个消息类型的层次结构。
为了在使用 fluent API 时能够访问子类的方法,我使用泛型对子类进行参数化,并使所有 fluent 方法(以“with”开头)返回泛型类型。请注意,我省略了 fluent 方法的大部分主体;他们进行了很多配置。
public abstract class Message<T extends Message<T>> {
protected Message() {
}
public T withID(String id) {
return (T) this;
}
}
具体的子类类似地重新定义了泛型。
public class CommandMessage<T extends CommandMessage<T>> extends Message<CommandMessage<T>> {
protected CommandMessage() {
super();
}
public static CommandMessage newMessage() {
return new CommandMessage();
}
public T withCommand(String command) {
return (T) this;
}
}
public class CommandWithParamsMessage extends
CommandMessage<CommandWithParamsMessage> {
public static CommandWithParamsMessage newMessage() {
return new CommandWithParamsMessage();
}
public CommandWithParamsMessage withParameter(String paramName,
String paramValue) {
contents.put(paramName, paramValue);
return this;
}
}
此代码有效,即我可以实例化任何类并使用所有流畅的方法:
CommandWithParamsMessage msg = CommandWithParamsMessage.newMessage()
.withID("do")
.withCommand("doAction")
.withParameter("arg", "value");
以任何顺序调用流利的方法是这里的主要目标。
但是,编译器警告所有return (T) this 都是不安全的。
类型安全:从 Message 到 T 的未经检查的强制转换
我不确定如何重新组织层次结构以使这段代码真正安全。尽管它有效,但以这种方式使用泛型确实令人费解。 特别是,如果我忽略警告,我无法预见会发生运行时异常的情况。 会有新的消息类型,所以我需要保持代码的可扩展性。 如果解决方案是完全避免继承,我还想获得替代建议。
在 SO 上有 other questions 解决了类似的问题。他们指出了一个解决方案,其中所有中间类都是抽象的,并声明了一个类似protected abstract self() 的方法。不过,到头来还是不安全的。
【问题讨论】:
-
代码不安全,是吗?你怎么知道
Message的类型是T? -
@EvanKnowles 因为
T extends Message<T>. -
@Will 但 abstract API 不知道这将永远成立
-
@MattCoubrough:实际上我认为是。本质上,OP 需要的是超类方法返回调用它们的实际对象的类,并且由于 Java 的设计,我们仅限于使用泛型。注意这个问题和这个问题类似:stackoverflow.com/questions/4031857/…
标签: java generics fluent-interface