lundi 19 décembre 2016

How to subclass a Java builder class?

I have two builders - PayloadA and PayloadB. To make example simpler, I have removed lot of other fields.

  • PayloadA.Builder constructor takes processName, genericRecord as an input parameter and then extract few things from genericRecord. And on that I am doing validation.
  • PayloadB.Builder constructor also takes processName, genericRecord as an input parameter and then it extract few different things from genericRecord as compared to above. And on those different fields I am doing validation.

As you can see, common thing between those two Payload?.Builder is processName, genericRecord, extracting oldTimestamp value and then isValid method.

Below is my PayloadA class:

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
}

Below is my PayloadB class:

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

}

Now is there any way I can use concept of abstract class here? I can create an abstract class Payload but what should be the stuff inside my abstract class:

public final class PayloadA extends Payload { ... }
public final class PayloadB extends Payload { ... }

And then once I build both my builder, I will pass it to some other method and there I want to access all the fields using getters. So let's say I have build PayloadA so I will send to execute method as shown belo and then in that method, I want to extract all the fields of PayloadA. Similarly if I send PayloadB to execute method, then I want to extract all the fields of PayloadB class using getters. How can I do this?

private void execute(Payload payload) {

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

Aucun commentaire:

Enregistrer un commentaire