gpt4 book ai didi

java - 具有继承和泛型的流畅 API

转载 作者:IT老高 更新时间:2023-10-28 21:14:34 24 4
gpt4 key购买 nike

我正在编写一个流畅的 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 都是不安全的。

Type safety: Unchecked cast from Message to T

我不确定如何重新组织层次结构以使这段代码真正安全。尽管它有效,但以这种方式使用泛型确实令人费解。特别是,如果我忽略警告,我无法预见会发生运行时异常的情况。会有新的消息类型,所以我需要保持代码的可扩展性。如果解决方案是完全避免继承,我还想获得替代建议。

other questions在 SO 上解决了类似的问题。他们指出了一个解决方案,其中所有中间类都是抽象的,并声明了一个像 protected abstract self() 这样的方法。不过,到头来还是不安全的。

最佳答案

您的代码基本上是对泛型的不安全使用。例如,如果我编写了一个扩展消息的新类,比如 Threat,并有一个新方法 doSomething(),然后我创建了一个由这个新类参数化的消息,它创建了一个 Message 的实例,然后尝试对其进行转换到它的子类。但是,由于它是 Message 的实例,而不是 Threat 的实例,因此尝试调用此消息将导致异常。因为 Message 不可能 doSOthing()。

此外,这里也没有必要使用泛型。普通的旧继承可以正常工作。由于子类型可以通过使其返回类型更具体来覆盖方法,因此您可以:

public abstract class Message {

protected Message() {

}

public Message withID(String id) {
return this;
}
}

然后

public class CommandMessage extends Message {

protected CommandMessage() {
super();
}

public static CommandMessage newMessage() {
return new CommandMessage();
}

public CommandMessage withCommand(String command) {
return this;
}
}

这可以正常工作,前提是您以正确的顺序调用参数:

CommandWithParamsMessage.newMessage()
.withID("do")
.withCommand("doAction")
.withParameter("arg", "value");

会失败,但是

CommandWithParamsMessage.newMessage().withParameter("arg", "value")
.withCommand("doAction").withID("do")

会成功,因为它只是“向上类型”,最后返回一个“消息”类。如果你不希望它“uptype”,那么只需覆盖继承的命令,现在你可以按任何顺序调用方法,因为它们都返回原始类型。

例如

public class CommandWithParamsMessage extends
CommandMessage {

public static CommandWithParamsMessage newMessage() {
return new CommandWithParamsMessage();
}

public CommandWithParamsMessage withParameter(String paramName,
String paramValue) {
contents.put(paramName, paramValue);
return this;
}

@Override
public CommandWithParamsMessage withCommand(String command){
super.withCommand(command);
return this;
}

@Override
public CommandWithParamsMessage withID(String s){
super.withID(s);
return this;
}
}

现在您将使用上述两个流畅调用中的任何一个流畅地返回 CommandWithParamsMessage。

这是否解决了您的问题,还是我误解了您的意图?

关于java - 具有继承和泛型的流畅 API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23731270/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com