5

I have two types of payload coming from upstream: It's either PayloadA or PayloadB.

PayloadA containes these many fields:

createTimestamp
sentTimestamp
schemaId
eventId
producerId
guid
deviceId
langId
sessionId

PayloadB containes these many fields:

createTimestamp
sentTimestamp
schemaId
eventId
producerId
eventType
payloadVersion
creationDate
expirationSeconds
payload

So first 5 fields are common between them. And in general they will have more fields.

I want to create a thread safe builder pattern for this. So should I have one Payload builder pattern class with all the fields from both the payload combined in it? Or I should have PayloadA and PayloadB builder pattern class inside another Payload builder class and the common fields of PayloadA and PayloadB will be part of Payload class?

What is the best way to make a builder pattern for this kind of problem. Let's say for PayloadA builder pattern deviceId is mandatory field. And for PayloadB builder pattern eventType is mandatory field.

john
  • 11,311
  • 40
  • 131
  • 251
  • Move common attributes to different class like payload. Use composition of payload class in payloadA and payloadB. Have a look at : http://stackoverflow.com/documentation/design-patterns/1811/builder-pattern/17177/builder-pattern-in-java-with-composition – Ravindra babu Dec 06 '16 at 02:18
  • @Ravindrababu Can you provide an example how that would look like? It will help me to understand better. – john Dec 06 '16 at 17:08

1 Answers1

2

I would recommend using a static nested builder (item 2) pattern here.

Here's what you can do

  1. Create an abstract class Payload with common attributes
  2. Create PayloadA and PayloadB which extend Payload with a static nested Builder for each.
  3. Leave thread safety to be handled by the method using/constructing these objects (there is no need for the Builder to be thread safe).

Payload

public abstract class Payload {

    private String createTimestamp;
    private String sentTimestamp;
    private String schemaId;
    private String eventId;
    private String producerId;

    //getters, setters, equals, hashcode, toString, compareTo, etc.
}

PayloadA (PayloadB would be similar)

class PayloadA extends Payload {
    private String guid;
    private String deviceId;
    private String langId;
    private String sessionId;

    private PayloadA() {
        //avoid direct instantiation
    }

    public static class Builder {

        private String guid;
        private String deviceId;
        private String langId;
        private String sessionId;

        public Builder setLangId(String langId) {
            this.langId = langId;
            return this;
        }

        public Builder(String deviceId) {
            //validations
            this.deviceId = deviceId;
        }

        public PayloadA build() {
            //validations
            return new PayloadA();
        }

        //other setters returning this Builder
    }
}

Usage (construct the appropriate Payload from the upstream data

public Payload constructPayload(final Data data) {

    //implement any thread safety mechanism as requirdhere. 
    // synchronized is just for explanatory purposes
    synchronized (data) {
        if (data.getType().equals("PayloadA")) {
            return new PayloadA.Builder(data.getDeviceId())
                    //.setGuid("someGuid")
                    //other setters
                    .build();
        } else {
            return new PayloadB.Builder(data.getEventType())
                    //.setCreationDate("someCreationDate")
                    // other setters
                    .build();
        }
    }
}

Hope this helps.

Pravin Sonawane
  • 1,803
  • 4
  • 18
  • 32
  • This looks quite promising. Now let's say if there is a field in Payload class which gets derived basis on few fields from PayloadA or PayloadB class whether they are set or not. How we will do that? This was possible if we make one big builder pattern Payload class and then in the constructor we can check whether that field was set or not and then basis on that derived the value for that variable. – john Dec 06 '16 at 04:07
  • If a field of the parent class is derived based on other fields of the parent and/or its subclass, the setters of these 'other' fields can update the parent field value when called. – Pravin Sonawane Dec 06 '16 at 04:11
  • @david the problem with one big builder is that if you set one property of of PayloadA and one of PayloadB, what will you be building eventually? – Pravin Sonawane Dec 06 '16 at 04:31
  • how to access common fields defined in Payload class? – AnAndroid Mar 24 '23 at 07:12