我为一个类制作了一个函数式构建器,它的工作方式如下

new ComponentStatus.Builder()
        .with($ -> {
          $.name = element.getName();
          $.state = element.getState();
          $.status = element.getStatus();
          $.description = element.getStatusDescription();
        }).build();

这个班级是

public class ComponentStatus {

  private final String name;
  private final int state;
  private final int status;
  private final String description;

  ComponentStatus(String name, int state, int status, String description) {
    this.name = name;
    this.state = state;
    this.status = status;
    this.description = description;
  }

  public static class Builder {

    public String name;
    public int state;
    public int status;
    public String description;

    Builder with(
        Consumer<Builder> builderFunction) {
      builderFunction.accept(this);
      return this;
    }

    ComponentStatus build() {
      return new ComponentStatus(name, state, status, description);
    }

  }
}

它起作用了.现在,我想向其他类添加一个构建器. with()方法始终是相同的,所以我try 创建一个接口以保存在样板文件中

public interface Buildable {

  default Buildable with(
      Consumer<Buildable> builderFunction) {
    builderFunction.accept(this);
    return this;
  }

    Object build();
}

这不起作用,因为with()返回Buildable而不是<? extends Buildable>,但是更改返回类型也不起作用.怎么办呢?

推荐答案

若要解决此问题,可以使用带有自引用类型参数的泛型.

下面是你如何定义你的Buildable界面:

import java.util.function.Consumer;

public interface Buildable<T extends Buildable<T>> {

    default T with(Consumer<T> builderFunction) {
        builderFunction.accept((T) this);
        return (T) this;
    }

    Object build();
}

现在更新您的ComponentStatus.Builder类以实现Buildable:

public static class Builder implements Buildable<Builder> {

    public String name;
    public int state;
    public int status;
    public String description;

    @Override
    public ComponentStatus build() {
        return new ComponentStatus(name, state, status, description);
    }
}

这样,with方法将返回正确的构建器类型,允许方法链接,但是它将向编译器发出关于"未判断的强制转换"的警告,因为不能保证这真的与T匹配.

为了避免这种情况,您可以使用抽象类而不是接口.以下是方法:

public abstract class AbstractBuilder<T extends AbstractBuilder<T>> {
  
  protected abstract T self();
  
  public T with(Consumer<T> builderFunction) {
    builderFunction.accept(self());
    return self();
  }
  
  public abstract Object build();
}

在每个混凝土构建器中,覆盖self()以返回this,正确键入:

public static class Builder extends AbstractBuilder<Builder> {
  
  public String name;
  public int state;
  public int status;
  public String description;
  
  @Override
  protected Builder self() {
    return this;
  }

  @Override
  public ComponentStatus build() {
    return new ComponentStatus(name, state, status, description);
  }
}

这种方法避免了未经判断的强制转换,并维护了类型安全.

Java相关问答推荐

Spring Webocket:尽管凭据设置为False,但MLhttpsify和Fetch请求之间的CORS行为存在差异

需要一个找不到的jakarta.sistence.EntityManager类型的Bean

如何在带有Micronaut的YAML中使用包含特殊字符的字符串作为键

在运行MVN测试时,为什么构建失败,并显示了java.lang.ClassNotFoundException:java.net.http.HttpResponse?

Domino Designer 14中的保存代理添加了重影库

如何将Java文档配置为在指定的项目根目录中生成?

使用htmlunit和java单击按钮

Java Telnet客户端重复的IAC符号

buildDir:File!&#的getter解决方案是什么?39.被抛弃

如何获得凌空cookies ,并设置它在下一个请求- android

在java中使用不同的application.properties-jar而不使用Spring

为什么相同的数据条码在视觉上看起来不同?

在实例化中指定泛型类型与不指定泛型类型之间的区别

如何在Spring Security中设置一个任何人都可以打开的主页?

如何修复Spring Boot应用程序中的RestDocumentationGenerationException:java.io.FileNotFoundException:/curl-request.adoc(只读文件系统)?

让标签占用JavaFX中HBox的所有可用空间

如何使用Rascal Evaluator从编译的JAR访问Rascal函数?

java.lang.ClassCastException:com.google.firebase.FirebaseException无法转换为com.google.fire base.auth.FirebaseAuthException

OpenJDK20:JEP434:Foreign Function&;内存API(第二次预览)

将在 Docker 中运行的 Spring Boot 连接到在 Docker 中运行的 PostgreSQL,无需 compose 文件?