如何子class一个Java建设者class?

How to subclass a Java builder class?

我有两个生成器 - PayloadAPayloadB。为了使示例更简单,我删除了很多其他字段。

如您所见,这两个 Payload?.Builder 之间的共同点是 processNamegenericRecord、提取 oldTimestamp 值然后 isValid 方法。

下面是我的PayloadAclass:

public final class PayloadA {
  private final String clientId;
  private final String deviceId;
  private final String processName;
  private final GenericRecord genericRecord;
  private final Long oldTimestamp;

  private PayloadA(Builder builder) {
    this.clientId = builder.clientId;
    this.deviceId = builder.deviceId;
    this.processName = builder.processName;
    this.genericRecord = builder.genericRecord;
    this.oldTimestamp = builder.oldTimestamp;
  }

  public static class Builder {
    private final String processName;
    private final GenericRecord genericRecord;
    private final String clientId;
    private final String deviceId;
    private final Long oldTimestamp;

    public Builder(PayloadA payload) {
      this.processName = payload.processName;
      this.genericRecord = payload.genericRecord;
      this.clientId = payload.clientId;
      this.deviceId = payload.deviceId;
      this.oldTimestamp = payload.oldTimestamp;
    }

    public Builder(String processName, GenericRecord genericRecord) {
      this.processName = processName;
      this.genericRecord = genericRecord;
      this.clientId = (String) DataUtils.parse(genericRecord, "clientId");
      this.deviceId = (String) DataUtils.parse(genericRecord, "deviceId");
      this.oldTimestamp = (Long) DataUtils.parse(genericRecord, "oldTimestamp");
    }

    // calling this method to validate
    public boolean isValid() {
      return isValidClientIdDeviceId();
    }

    private boolean isValidClientIdDeviceId() {
        // validate here
    }

    public PayloadA build() {
      return new PayloadA(this);
    }
  }

  // getter here
}

下面是我的PayloadBclass:

public final class PayloadB {
  private final GenericRecord genericRecord;
  private final String processName;
  private final String type;
  private final String datumId;
  private final Long oldTimestamp;

  private PayloadB(Builder builder) {
    this.processName = builder.processName;
    this.genericRecord = builder.genericRecord;
    this.type = builder.type;
    this.datumId = builder.datumId;
    this.oldTimestamp = builder.oldTimestamp;
  }

  public static class Builder {
    private final GenericRecord genericRecord;
    private final String processName;
    private final String type;
    private final String datumId;
    private final Long oldTimestamp;

    public Builder(PayloadB payload) {
      this.processName = payload.processName;
      this.genericRecord = payload.genericRecord;
      this.type = payload.type;
      this.datumId = payload.datumId;
      this.oldTimestamp = payload.oldTimestamp;
    }

    public Builder(String processName, GenericRecord genericRecord) {
      this.processName = processName;
      this.genericRecord = genericRecord;
      this.type = (String) DataUtils.parse(genericRecord, "type");
      this.datumId = (String) DataUtils.parse(genericRecord, "datumId");
      this.oldTimestamp = (Long) DataUtils.parse(genericRecord, "oldTimestamp");
    }

    // calling this method to validate
    public boolean isValid() {
      return isValidType() && isValidDatumId();
    }

    private boolean isValidType() {
        // validate here
    }

    private boolean isValidDatumId() {
        // validate here
    }

    public PayloadB build() {
      return new PayloadB(this);
    }
  }

    // getter here

}

现在有什么方法可以在这里使用抽象概念 class 吗?我可以创建一个摘要 class Payload 但我的摘要 class:

中应该包含哪些内容
public final class PayloadA extends Payload { ... }
public final class PayloadB extends Payload { ... }

然后,一旦我构建了两个构建器,我会将其传递给其他方法,然后我想使用 getter 访问所有字段。所以假设我已经构建了 PayloadA,所以我将发送到执行方法,如下所示,然后在该方法中,我想提取 PayloadA 的所有字段。同样,如果我将 PayloadB 发送到执行方法,那么我想使用 getter 提取 PayloadB class 的所有字段。我该怎么做?

private void execute(Payload payload) {

    // How can I access fields of PayloadA or PayloadB 
    // depending on what was passe
}

仅当上述字段碰巧不常见时,才为有效负载创建一个超级 class。您可以在其中移动公共字段和方法(但不能移动构建器)。您甚至可以为构建器创建一个超级 class,但它可能会使代码过于混乱。

如果您真的需要有效负载 super class,那么您可以使用 Visitor Pattern:

实现您的 execute 方法

首先,您必须创建一个访问者,您可以在其中访问您的具体 classes:

public class PayloadVisitor {

    public void visit(PayloadA payloadA) {
        // use payload A here
    }

    public void visit(PayloadB payloadB) {
        // use payload B here
    }
}

然后你必须添加一个方法到你的超级class接受访问者:

public abstract class Payload {

    // common fields and methods

    public abstract void accept(PayloadVisitor visitor);
}

覆盖子class中的方法accept:

public final class PayloadA extends Payload {

    // ...

    @Override
    public void accept(PayloadVisitor visitor) {
        visitor.visit(this);
    }
}

public final class PayloadB extends Payload {

    // ...

    @Override
    public void accept(PayloadVisitor visitor) {
        visitor.visit(this);
    }
}

您的方法 execute 只是将调用重定向到相应的 visit 方法:

private void execute(Payload payload) {
    payload.accept(new PayloadVisitor());
}

访客模式可能会让人不知所措。也可以简单点,用instanceof来确定具体的class.

我认为这里的问题是 PayloadA 和 PayloadB 是否在设计中共享一些意义完整的东西。如果除了一个参数之外逻辑在某种程度上是相同的,那么你可以有一个 class.

也许你可以有抽象class,对于特定领域的实现你可以return你对特定实现的具体值。

例如 Abstract class 有一个字段的抽象 setter/getter ,当您将该方法实现到 PayloadA 和 PayloadB 时,您可以 return 您想要的字段。

我认为问题是这里的设计而不是如何去做。看看你的 class 是什么,然后你有很多选择