1

У меня есть два строителя - PayloadA и PayloadB. Чтобы упростить пример, я удалил много других полей.Как подклассы класса Java-строителя?

  • PayloadA.Builder конструктор принимает processName, genericRecord в качестве входного параметра, а затем извлечь несколько вещей из genericRecord. И на этом я делаю валидацию.
  • PayloadB.Builder конструктор также принимает processName, genericRecord как входной параметр, а затем извлекает несколько разных вещей от genericRecord по сравнению с предыдущим. И на тех разных полях я делаю проверку.

Как вы можете видеть, общая вещь между этими двумя Payload?.Builder является processName, genericRecord, извлекая oldTimestamp значение, а затем isValid метод.

Ниже мой PayloadA класс:

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 
} 

Ниже мой PayloadB класс:

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 

} 

Теперь есть ли способ я могу использовать понятие абстрактного класса здесь? Я могу создать абстрактный класс Payload но то, что должно быть вещи внутри моего абстрактного класса:

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

А потом однажды я построю как мой строитель, я передам его в какой-то другой метод, и там я хочу, чтобы доступ ко всем поля с использованием геттеров. Итак, допустим, у меня есть PayloadA, поэтому я отправлю для выполнения метода, как показано ниже, а затем в этом методе, я хочу извлечь все поля PayloadA. Аналогично, если я отправлю PayloadB для выполнения метода, я хочу извлечь все поля класса PayloadB с использованием геттеров. Как я могу это сделать?

private void execute(Payload payload) { 

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

* но что должно быть материалом внутри моего абстрактного класса *, который является общим для обоих. –

ответ

1

Создайте суперклассу для полезной нагрузки, только если указанные поля не являются обычным совпадением. Вы можете перемещать общие поля и методы (но не строители) там. Вы даже можете создать суперкласс для строителей, но он, вероятно, слишком сильно загромождает код.

Если у вас действительно есть использовать для полезной нагрузки супер класса, то вы можете реализовать свой execute метод с Visitor Pattern:

Во-первых, вы должны создать посетителя, где вы можете получить доступ к конкретным классам:

public class PayloadVisitor { 

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

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

Затем вы должны добавить метод к вашему суперкласса прием посетителей:

public abstract class Payload { 

    // common fields and methods 

    public abstract void accept(PayloadVisitor visitor); 
} 

Override метод accept в подклассов:

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

Ваш метод execute просто перенаправляет вызов в соответствии visit способом:

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

Паттерн посетитель может быть огромным. Вы также можете сохранить его простым и использовать instanceof, чтобы определить конкретный класс.

+0

Смогу ли я получить доступ ко всем полям PayloadA или PayloadB при выполнении метод тогда? Я смущаюсь в этой части. – john

+0

Нет, вы не можете получить доступ к полям «PayloadA» или «PayloadB» в методе 'execute'. Но метод 'execute' вызывает соответствующий метод' accept' 'PayloadA' или' PayloadB' из-за позднего связывания. Метод 'accept' в свою очередь вызывает перегруженный метод' visit'. В рамках метода 'visit' вы можете получить доступ к определенным полям, и здесь вы пишете свой код. –

0

Я думаю, что вопрос здесь в том, что PayloadA и PayloadB делятся чем-то смыслом, полным для дизайна. Если логика как бы то же самое, кроме одного параметра, то вы можете иметь один класс.

Возможно, у вас может быть абстрактный класс, а для реализации для определенного поля вы можете вернуть свое конкретное значение для конкретной реализации.

Например, абстрактный класс имеет абстрактный сеттер/getter для поля, а когда вы реализуете этот метод для PayloadA и PayloadB, вы можете вернуть нужное поле.

Я думаю, что проблема в дизайне здесь не для того, чтобы это сделать. Посмотрите, каковы ваши классы на самом деле, а затем у вас есть много вариантов.