Subclassing abstract class 在构建器模式中?

Subclassing abstract class in a builder pattern?

我有两种来自上游的负载:PayloadAPayloadB。与 PayloadB 相比,PayloadA 中有很多字段,但 PayloadAPayloadB 之间有一些共同的字段。为了使示例更简单,我只添加了几个字段。

下面是 PayloadA 的生成器 class:

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
}

下面是 PayloadB 的 class:

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
}

现在我创建了另一个 class,它是 Payload class,其中我有 PayloadAPayloadB 的所有公共字段,所以我还必须以某种方式设置这些字段,我不确定如何在下面使用 class:

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

  // getters and setters here
}

问题:

现在根据传递的内容,我根据下面的代码制作 PayloadAPayloadB

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

并且在 DataProcessor process 方法中:

  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?
  }

现在如何在process方法中设置createTimestampkey变量Payloadclass?现在我有一个 运行 方法来区分它,但通常我会有不同的 PayloadA 上游代码和不同的 PayloadB 上游代码,因此我们将使用 Payload class 中的任何一个.

另外,我应该让两个不同的建筑商在这里做所有事情还是让一个大建筑商在这里做所有事情?

PayloadAPayloadB 可以扩展 Payload 如下所示:

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 or PayloadB inside process()?

你可以发现使用instanceof就像payloadinstanceofPayloadA一样,如上图。但是,一般来说,使用 instanceof 检查来编写代码并不是一个好主意,所以除非不可避免,否则不要使用它。

Should I have two different builders here or one big builder here doing everything?

根据您在上面提供的代码,这些字段 PayloadAPayloadB 完全不同,因此最好保留单独的 bean 和各自的构建器。

UPDATE: I need to figure out what type of payload it is and basis on that I need to set values for key variable?

内部 setKey() 将在传递给 process(Payload payload) 的对象类型上被调用(多态性,OOP 的基本原则之一)即,如果您从 [ 传递 PayloadA 对象=27=] 方法,将调用 PayloadA 对象上的 setKey()总而言之,您根本不需要 instanceof 检查。 这取决于您的要求,您希望在哪里设置密钥,它可以在 process() 方法(如果你有一些其他依赖项来生成 key)或者可以按照@Roberto

的建议完成
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();
}

编辑:

这里的想法是任何 class 扩展有效负载必须实现 setKey() 方法,或者本身是抽象的。因此,PayloadA 和 PayloadB 都实现了该方法。每个 class 提供不同的实现。

现在假设你

PayloadA pa = new PayloadA();
pa.setKey()

不出所料,实际执行的实现将是PayloadA中定义的实现。

现在考虑这个案例:

Payload pa = new PayloadA();
pa.setKey()

尽管声明的变量类型为 Payload,但变量引用的对象的实际类型是 PayloadA,因此 setKey() 调用是 PayloadA 中的调用。这被称为动态调度,因为调用哪个实现在 运行 时是已知的,而不是在编译时

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