1

Ich habe zwei Builder - PayloadA und PayloadB. Um das Beispiel zu vereinfachen, habe ich viele andere Felder entfernt.Wie wird eine Java-Builder-Klasse abgeleitet?

  • PayloadA.Builder Konstruktor processName, genericRecord als Eingabeparameter und extrahieren paar Dinge aus genericRecord. Und damit mache ich Validierung.
  • PayloadB.Builder Konstruktor nimmt auch processName, genericRecord als Eingabeparameter und extrahieren es einige verschiedene Dinge von genericRecord wie oben verglichen. Und auf diesen verschiedenen Gebieten mache ich Validierung.

Wie Sie sehen können, gemeinsame Sache zwischen diesen beiden Payload?.Builder ist processName, genericRecord, oldTimestamp Wert zu extrahieren und dann isValid Methode.

Unten ist meine PayloadA Klasse:

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 
} 

Unten ist meine PayloadB Klasse:

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 

} 

Jetzt ist es eine Möglichkeit, die ich hier Begriff der abstrakten Klasse verwenden kann? Ich kann eine abstrakte Klasse Payload erstellen, aber was soll das Zeug in meinem abstrakte Klasse sein:

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

Und dann, wenn ich meine beiden Baumeister bauen, werde ich es auf eine andere Methode übergeben und dort möchte ich alle für den Zugriff auf die Felder mit Gettern. Also lassen Sie uns sagen, ich habe Build PayloadA, also werde ich senden, um die Methode wie unten gezeigt auszuführen und dann in dieser Methode möchte ich alle Felder von PayloadA extrahieren. Ähnlich, wenn ich PayloadB senden, um Methode auszuführen, dann möchte ich alle Felder von PayloadB Klasse mit getters extrahieren. Wie kann ich das machen?

private void execute(Payload payload) { 

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

* aber was sollte das Zeug in meinem abstrakten Klasse * Zeug sein, die beide gemeinsam ist –

Antwort

1

Erstellen Sie eine Superklasse für die Nutzdaten nur dann, wenn die genannten Felder nicht zufällig zusammenfallen. Sie können allgemeine Felder und Methoden (aber nicht die Builder) dorthin verschieben. Sie könnten sogar eine Superklasse für die Builder erstellen, aber es wird den Code wahrscheinlich zu sehr durcheinander bringen.

Wenn Sie wirklich eine Verwendung für die Nutzlast Superklasse haben, dann können Sie Ihre execute Methode mit dem Visitor Pattern implementieren:

Zuerst müssen Sie einen Besucher erstellen, wo Sie Ihre konkreten Klassen zugreifen können:

public class PayloadVisitor { 

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

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

Dann müssen Sie eine Methode, um Ihre Superklasse hinzufügen, die Besucher zu akzeptieren:

public abstract class Payload { 

    // common fields and methods 

    public abstract void accept(PayloadVisitor visitor); 
} 

Aufschalten der Methode accept in den Unterklassen:

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); 
    } 
} 

Ihre Methode execute leitet nur den Aufruf der nach visit Methode:

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

Das Besuchermuster kann überwältigend sein. Sie können es auch einfach halten und instanceof verwenden, um die konkrete Klasse zu bestimmen.

+0

Kann ich auf alle Felder von PayloadA oder PayloadB in der Ausführung zugreifen Methode dann? Ich bin verwirrt über diesen Teil. – john

+0

Nein, Sie können nicht auf die Felder 'PayloadA' oder' PayloadB' in der 'execute' Methode zugreifen. Aber die 'execute'-Methode ruft die entsprechende' accept'-Methode von 'PayloadA' oder 'PayloadB' wegen der späten Bindung auf. Die 'accept' Methode wiederum ruft die überladene' visit' Methode auf. Innerhalb der 'visit' Methode können Sie auf die spezifischen Felder zugreifen und hier schreiben Sie Ihren Code. –

0

Ich denke, die Frage hier ist, ob PayloadA und PayloadB etwas Bedeutung zusammen für das Design teilen. Wenn die Logik bis auf einen Parameter identisch ist, können Sie eine Klasse haben.

Vielleicht können Sie die abstrakte Klasse haben, und für die Implementierung für ein bestimmtes Feld können Sie Ihren konkreten Wert für eine bestimmte Implementierung zurückgeben.

Zum Beispiel Abstract Klasse hat abstrakte Setter/Getter für ein Feld und wenn Sie diese Methode zu PayloadA und PayloadB implementieren, können Sie das gewünschte Feld zurückgeben.

Ich denke, das Problem ist das Design hier nicht, wie es geht. Sehen Sie, was Ihre Klassen wirklich sind und dann haben Sie viele Optionen

Verwandte Themen