I have two builders - PayloadA
and PayloadB
. To make example simpler, I have removed lot of other fields.
PayloadA.Builder
constructor takesprocessName
,genericRecord
as an input parameter and then extract few things fromgenericRecord
. And on that I am doing validation.PayloadB.Builder
constructor also takesprocessName
,genericRecord
as an input parameter and then it extract few different things fromgenericRecord
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 below 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
}
Create a super class for the payloads only if the mentioned fields are not common by a coincidence. You can move common fields and methods (but not the builders) in there. You could even create a super class for the builders but it will probably clutter the code too much.
If you really have a use for the payload super class then you can implement your
execute
method with the Visitor Pattern:First, you have to create a visitor where you can access your concrete classes:
Then you have to add a method to your super class accepting the visitor:
Override the method
accept
in the subclasses:Your method
execute
just redirects the call to the accordingvisit
method:The visitor pattern can be overwhelming. You can also keep it simple and use
instanceof
to determine the concrete class.