Reputation: 11669
I have two types of payload coming from upstream: It's either PayloadA
or PayloadB
. PayloadA
has lot of fields in it as compared to PayloadB
but there are some common fields between PayloadA
and PayloadB
. Just to make example simpler, I have added only few fields.
Below is the builder class for PayloadA
:
public final class PayloadA {
private final String clientId;
private final String langid;
private final String deviceId;
private final Map<String, String> applicationPayload;
// other fields as well
private PayloadA(Builder builder) {
this.clientId = builder.clientId;
this.langid = builder.langid;
this.deviceId = builder.deviceId;
this.applicationPayload = builder.applicationPayload.build();
}
public static class Builder {
protected final String deviceId;
protected String clientId;
protected String langid;
protected ImmutableMap.Builder<String, String> applicationPayload = ImmutableMap.builder();
public Builder(String deviceId) {
this.deviceId = deviceId;
}
public Builder setClientId(String clientId) {
this.clientId = clientId;
return this;
}
public Builder setLangid(String langid) {
this.langid = langid;
return this;
}
public Builder setPayload(Map<String, String> payload) {
this.applicationPayload.putAll(payload);
return this;
}
public PayloadA build() {
return new PayloadA(this);
}
}
// getters and to string here
}
Now below is the class for PayloadB
:
public final class PayloadB {
private final String clientid;
private final String type;
private final String payId;
// other fields as well
private PayloadB(Builder builder) {
this.clientid = builder.clientid;
this.type = builder.type;
this.payId = builder.payId;
}
public static class Builder {
protected final String type;
protected String payId;
protected String clientid;
public Builder(String type) {
this.type = type;
}
public Builder setPayId(String payId) {
this.payId = payId;
return this;
}
public Builder setClientId(String clientid) {
this.clientid = clientid;
return this;
}
public PayloadB build() {
return new PayloadB(this);
}
}
// getters and to string here
}
Now I have created another class which is Payload
class in which I have all the common fields both for PayloadA
and PayloadB
so I have to set these fields as well somehow and I am not sure how to use below class:
public abstract class Payload {
private long createTimestamp;
private String key;
// some other fields are here
// getters and setters here
}
Question:
Now from the below code I am making either PayloadA
or PayloadB
depending on what is passed.
private void run(String name) {
// .. some code here
if (name.equalsIgnoreCase("PayloadA")) {
Payload payload =
new PayloadA.Builder(getDeviceId()).setClientId("someid").setLangid("anotherid")
.setPayload("some map").build();
DataProcessor.getInstance().process(payload);
} else {
Payload payload =
new PayloadB.Builder(getType()).setPayId("someid").setClientId("anotherid").build();
DataProcessor.getInstance().process(payload);
}
}
And in the DataProcessor
process
method:
private void process(Payload payload) {
// 1) here I need to set createTimestamp and key variables on payload bcoz they are common
// fields.
// 2) Also how can I figure out whether payload is PayloadA or PayloadB here?
}
Now how can I set createTimestamp
and key
variable which is in Payload
class in the process
method? Right now I have a run method where I am differentiating it but in general I will have a different upstream code for PayloadA and different upstream code for PayloadB so depending on that we will use either of the Payload class.
Also should I have two different builders here or one big builder here doing everything?
Upvotes: 0
Views: 1016
Reputation: 2228
public class Payload {
// common fields
private String clientid;
private String key;
private long Timestamp;
// setter and getters
}
public class PayloadA extends Payload implements PayloadStrategy {
// PayloadA specific fields
private String langid;
private String deviceId;
// setters and getters
public static class Builder {
// existing code
}
@Override
public void process() {
System.out.println("PayloadA specific implementation");
}
}
public class PayloadB extends Payload implements PayloadStrategy {
// PayloadA specific fields
private String type;
private String payId;
// setters and getters
public static class Builder {
// existing code
}
@Override
public void process() {
System.out.println("PayloadB specific implementation");
}
}
}
// define contract
public interface PayloadStrategy {
public void process();
}
// payload context
public class PayloadContext {
PayloadStrategy strategy;
public void setContext(PayloadStrategy payloadStrategy) {
this.strategy = payloadStrategy;
}
public void processPayload() {
strategy.process();
}
}
// parameterized (PayloadA or PayloadB) payload run method
PayloadContext context = new PayloadContext();
context.setContext(new PayloadA());
context.processPayload();
Upvotes: 0
Reputation: 1903
abstract public class Payload {
abstract void setKey();
}
public class PayloadA extends Payload {
//add existing code
void setKey() {
key = "a";
}
}
public class PayloadB extends Payload {
//add existing code
void setKey() {
key = "b";
}
}
private void process(Payload payload) {
//Depending upon the object passed, fields will be set for A or B
payload.setCreateTimestamp(ADD_DATA1);
payload.setKey();
}
Edit:
The idea here is that any class extending payload must either implement the setKey() method, or be abstract itself. so, PayloadA and PayloadB both implement the method. Each class provides a different implementation.
Now suppose you do
PayloadA pa = new PayloadA();
pa.setKey()
As expected, the implementation actually executed would be the one defined in PayloadA.
Now consider this case:
Payload pa = new PayloadA();
pa.setKey()
Despite the variable being declared of type Payload, the actual type of the object referred to by the variable is PayloadA, hence the setKey() call is the one in PayloadA. This is referred to as Dynamic Dispatching, because which implementation is called is known at run-time, not at compile time
Upvotes: 1
Reputation: 22402
PayloadA
and PayloadB
can extend Payload
as shown below:
public abstract class Payload {
private long createTimestamp;
private String key;
// some other fields are here
// getters and setters here
}
public class PayloadA extends Payload {
//add existing code
}
public class PayloadB extends Payload {
//add existing code
}
private void process(Payload payload) {
//Depending upon the object passed, fields will be set for A or B
payload.setCreateTimestamp(ADD_DATA1);
payload.setKey(ADD_DATA2);
//set other fields
//if(payload instanceof PayloadA) {
//payloadA
//}
}
How can I figure out whether payload is
PayloadA
orPayloadB
insideprocess()
?
You can find that using instanceof
like payload
instanceof
PayloadA
as shown above. But, in general, it is not a good idea to code using of instanceof
checks, so don't prefer to use it unless it can't be avoided.
Should I have two different builders here or one big builder here doing everything?
As per your provided code above, the fields are quite PayloadA
and PayloadB
different, so better to keep separate beans and respective builders.
UPDATE: I need to figure out what type of payload it is and basis on that I need to set values for key variable?
Inside setKey()
will be called on the object type passed to the process(Payload payload)
(polymorphism, one of the fundamental principles of OOP) i.e., if you pass PayloadA
object from run()
method, setKey()
on PayloadA
object will be called. To summarise, you don't need instanceof
checks at all for this. It is upto your requirement where do you want to set the Key, it could be inside process()
method (if you have some other dependencies to generate the key
) or it could be done as suggested by @Roberto
Upvotes: 1