// CommandBuilder.java
public class CommandBuilder {
public String name; // required
public String description = "Default Value"; //optional
public CommandBuilder(String name) {
this.name = name;
}
public CommandBuilder setDescription(String description) {
this.description = description;
return this;
}
public CommandBuilder build() {
return this;
}
}
// Command.java
public abstract class Command extends ListenerAdapter {
private String name;
private String description;
protected abstract void execCommand(MessageReceivedEvent event);
public Command(CommandBuilder builder) {
this.name = builder.name;
this.description = builder.description;
}
@Override
public void onMessageReceived(MessageReceivedEvent event) {
execCommand(event);
}
}
// ExampleCommand.java
public class ExampleCommand extends Command {
public ExampleCommand(CommandBuilder builder) {
super(builder);
}
@Override
protected void execCommand(MessageReceivedEvent event) {
// ...
}
}
// Bot.java
public class Bot() {
public static void main(String[] args) {
// ...
jdaBuilder.addEventListener(
new ExampleCommand(
new CommandBuilder("Example Command").setDescription("You know it.").build();
)
);
// ...
}
}
所以,我需要一些关于代码风格的建议。以上大致是我在JDA中的Discord bot的代码设置。 <{1}}做什么或jdaBuilder.addEventListener(Object)
是什么,并不重要。
在构造具有继承类型MessageReceivedEvent
的对象时,我使用构建器模式来避免过多的构造函数重载,因为在我的实际代码中,Command
类可以接受的不仅仅是两个参数。
Command
的问题是CommandBuilder
没有并且不能返回类型build()
的对象(因为它是抽象的)而是类型Command
本身, Command的子类作为参数(然后传递给CommandBuilder
)。
THAT的问题在于:
Command
,因为每个其他方法都返回build()
以及CommandBuilder
的子类可能会在主要内容中非常混乱。那么,解决这个问题的最佳方法是什么?我想过使用一个接口,但在我的抽象Command类中,有一些带有“默认”代码的方法,如果需要它们,子类可以选择覆盖它(但它不是必需的!)。
这些默认方法使用Command
类的其他方法,因此我不能将它们重构为接口作为真正的默认方法。
我的代码运行得很好,我只是认为通过我必须实例化对象的方式,我在某处做了错误的转向。关于如何重构或重写我的代码以遵循最佳Java实践的任何建议?
答案 0 :(得分:0)
也许你会像这样重构你的build()
:
public <T extends Command> T build(Function<CommandBuilder, T> constructor) {
return constructor.apply(this);
}
这种方式允许构建器接受任何构造函数引用,例如
FooCommand cmd = builder.build(FooCommand::new);
也许另外你可以添加适当的代码,或者允许反射,以便
FooCommand cmd = builder.build(FooCommand.class);
也可以使用,但如果你没有匹配的构造函数,那么前者的优势在于编译时错误。