在构建器模式中对抽象类进行子类化?

时间:2016-12-06 22:07:59

标签: java design-patterns fluent builder-pattern

我有两种来自上游的有效负载:它是PayloadAPayloadB。与PayloadA相比,PayloadB中包含大量字段,但PayloadAPayloadB之间存在一些共同字段。为了简化示例,我只添加了几个字段。

以下是PayloadA的构建器类:

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的类:

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
}

现在我创建了另一个类Payload类,其中我有PayloadAPayloadB的所有公共字段,所以我必须设置这些字段以及我我不确定如何使用下面的课程:

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

现在,如何在createTimestamp方法中设置key类中的Payloadprocess变量?现在我有一个运行方法,我区分它,但一般来说,我将有一个不同的PayloadA上游代码和PayloadB的不同上游代码,所以根据我们将使用任何一个Payload类。

我也应该在这里有两个不同的建造者或一个大建筑师在做什么吗?

3 个答案:

答案 0 :(得分:1)

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

如何确定有效负载是PayloadA还是PayloadB   在process()内?

您可以使用instanceof payload instanceof PayloadA来查找,如上所示。但是,一般来说,使用instanceof检查进行编码并不是一个好主意,所以除非无法避免,否则不要使用它。

  

我在这里应该有两个不同的建造者还是一个大建筑商   干什么?

根据您提供的代码,字段非常PayloadAPayloadB不同,因此最好保留单独的bean和各自的构建器。

  

更新:我需要弄清楚它的有效载荷类型和基础   我需要为关键变量设置值吗?

内部setKey()将在传递给process(Payload payload)的对象类型上调用(多态,OOP的基本原则之一),即,如果从{{1}传递PayloadA对象方法,将调用run()对象上的setKey()总结一下,您根本无需进行PayloadA检查。根据您的要求,您要在哪里设置密钥,它可能位于instanceof方法内(如果你有一些其他的依赖关系来生成process()),或者它可以按照@Roberto的建议完成

答案 1 :(得分:1)

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

修改

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

现在假设你做了

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

正如预期的那样,实际执行的实现将是PayloadA中定义的实现。

现在考虑一下这个案例:

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

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

答案 2 :(得分:0)

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