gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 04:27:15 24 4
gpt4 key购买 nike

我正在编写一个流畅的 API 来配置和实例化一系列“消息”对象。我有一个消息类型层次结构。

为了在使用 Fluent API 时能够访问子类的方法,我使用泛型来参数化子类,并使所有 Fluent 方法(以“with”开头)返回泛型类型。请注意,我省略了 fluid 方法的大部分主体;其中进行了很多配置。

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/56603128/

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