如何遵循对抽象超类的子类使用构建器模式的最佳 Java 实践?

How to follow best Java practices using builder pattern for a subclass of an abstract superclass?

// 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 机器人设置的代码。 jdaBuilder.addEventListener(Object) 做什么或 MessageReceivedEvent 做什么并不重要。

我使用构建器模式来避免构造具有继承类型 Command 的对象时过多的构造函数重载,因为在我的实际代码中 Command class 可以接受的不仅仅是两个参数。 CommandBuilder 的问题是 build() 没有也不能 return 类型为 Command 的对象(因为它是抽象的)而是类型 CommandBuilder本身,Command 的每个 subclass 作为参数(然后传递给 Command)。 return 中的问题在于:

  1. 不需要调用 build(),因为每个其他方法 return 都是 CommandBuilder 以及
  2. 具有 4-6 个参数的 Command 的子 class 的实例化可能会使主体变得 非常 混乱。

那么,解决这个问题的最佳方法是什么?我想过使用一个接口,但是在我的抽象命令 class 中有一些带有 "default" 代码的方法,subclasses 可以选择覆盖如果他们需要它(但它不是必需的!)。 这些默认方法利用了 Command class 的其他方法,因此我不能将它们作为真正的默认方法重构到接口中。

我的代码工作得很好,我只是觉得我必须实例化我的对象的方式,我在某处走错了路。关于如何重构或重写我的代码以遵循最佳 Java 实践的任何建议?

也许你应该像这样重构你的 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);

也可以使用,但前者的优点是如果您没有匹配的构造函数,它会出现编译时错误。