Использование абстрактного класса в шаблоне построителя?

У меня есть два типа полезных данных, поступающих из восходящего потока: это либо PayloadA, либо PayloadB. Между PayloadA и PayloadB есть несколько общих полей, поэтому я создал класс Payload с этими общими полями, а для остальных я создал два класса-строителя, по одному для каждой полезной нагрузки.

Ниже приведен класс построителя для PayloadA:

public final class PayloadA {
  private final String clientId;
  private final String langid;
  private final String deviceId;
  private final Map<String, String> applicationPayload;

  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
}

Ниже приведен класс для PayloadB:

public final class PayloadB {
  private final String clientid;
  private final String type;
  private final String payId;

  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
}

Теперь я создал еще один класс, который является классом Payload (это должен быть абстрактный класс?), в котором у меня есть все общие поля как для PayloadA, так и для PayloadB, поэтому я должен как-то установить эти поля, и я не уверен, как использовать ниже класса:

public abstract class Payload {
  private long createTimestamp;
  private String partition;
  private String key;
  // some other fields here

  // getters and setters here
}

Вопрос:

  • Теперь предположим, что если мы получаем PayloadB из восходящего потока, то я хочу, чтобы поле key в классе Payload было равно значению type в классе PayloadB во всех строчных буквах, и если мы получаем PayloadA из восходящего потока, то я хочу, чтобы ключ был world.
  • А также, если мы получаем PayloadB из восходящего потока, и если было установлено clientId, то я хочу, чтобы partition было 15, и если мы получаем PayloadA из восходящего потока, и если было установлено clientId, то я хочу, чтобы partition было 15, но если оно не было установлено, а langId было там , то я хочу, чтобы partition было 17.
  • И я также хочу установить createTimestamp, что я должен сделать после создания объекта Payload. Так, например, у меня есть объект PayloadA, и он будет передан другому классу, и там мне нужно установить значение createTimestamp для объекта PayloadA. Не знаете, как это сделать? Я должен что-то клонировать?

Как я могу использовать класс Payload в моем шаблоне строителя? Я получу две разные полезные нагрузки, и в них будет мало общего, поэтому общие поля я разделил их в абстрактном классе.

Должен ли я иметь большой класс шаблонов строителей со всем в нем или несколько шаблонов строителей, расширяющих что-то?


person john    schedule 06.12.2016    source источник
comment
Для начала, почему вы используете строителей? Похоже, что код переработан...   -  person Spotted    schedule 06.12.2016
comment
В общем, все эти Payload имеют много полей. Чтобы сделать пример более простым для понимания, я сделал его таким.   -  person john    schedule 06.12.2016
comment
Итак, вы представили строителей из-за огромных классов. Вы уже думали о рефакторинге в меньших классах, решая, таким образом, корень проблемы? На данный момент ваша проблема звучит для меня как XYProblem: вы спрашиваете, как использовать абстрактный класс в конструкторе (который это что-то очень необычное) вместо того, чтобы спросить себя, почему я оказался в такой странной конструкции?   -  person Spotted    schedule 07.12.2016
comment
хм, тогда как мне подойти к этой проблеме?   -  person john    schedule 07.12.2016
comment
Для чего вам нужен PayloadX ? Это DTO или BO? Содержат ли они на самом деле какую-то бизнес-логику или это всего лишь набор геттеров? Реально ли вы опубликовать полный код (по крайней мере, все атрибуты)?   -  person Spotted    schedule 07.12.2016


Ответы (1)


  • Я не буду передавать экземпляр builder конструктору PayloadX. Либо передайте значения как отдельные аргументы конструктора, либо вызовите установщики.
  • Вы можете определить Payload.Builder, который будет содержать общие поля PayloadA и PayloadB. Этот класс будет абстрактным классом, объявляющим абстрактный метод build.
  • PayloadA.Builder и PayloadB.Builder будут расширять Payload.Builder, реализуя метод build.
  • В этом методе build вы реализуете любую пользовательскую логику, необходимую для создания и установки полей файла PayloadX.

Похоже, вы хотите сделать свой класс неизменным (кстати, будьте осторожны с applicationPayload). В этом случае вы не можете ничего «установить». Вы можете создать только новый экземпляр. Есть много способов сделать это, например, вы можете реализовать метод PayloadX withTimestamp(...). Или вы можете расширить свою сборку, чтобы принять PayloadX и установить там отметку времени, что приведет к чему-то вроде new PayloadX.Builder(payloadXInstance).setTimestamp(...).build().

person lexicore    schedule 06.12.2016
comment
Можете ли вы привести пример всех ваших вышеперечисленных предложений? Это поможет мне лучше понять. На данный момент я запутался, как использовать ваше предложение. - person john; 06.12.2016
comment
@david Я не буду, извините, это превышает количество времени, которое я готов внести. - person lexicore; 06.12.2016