【问题标题】:Subclassing abstract class in a builder pattern?在构建器模式中子类化抽象类?
【发布时间】:2016-12-06 22:07:59
【问题描述】:

我有两种来自上游的有效负载:PayloadAPayloadB。与PayloadB 相比,PayloadA 有很多字段,但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);
    }
  }

DataProcessorprocess方法中:

  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 方法中设置Payload 类中的createTimestampkey 变量?现在我有一个运行方法,我正在区分它,但总的来说,我将为 PayloadA 提供不同的上游代码,为 PayloadB 提供不同的上游代码,因此我们将使用任一 Payload 类。

我还应该在这里有两个不同的建设者还是一个大建设者来做所有事情?

【问题讨论】:

    标签: java design-patterns fluent builder-pattern


    【解决方案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 还是PayloadBprocess()里面?

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

    我应该在这里有两个不同的建设者还是一个大建设者 什么都做?

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

    更新:我需要弄清楚它是什么类型的有效载荷以及基于 我需要为关键变量设置值吗?

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

    【讨论】:

    • 所以如果我不使用 instanceOf 那么我应该使用什么? Bcoz 在处理方法中,我需要弄清楚它是什么类型的有效负载,并在此基础上为key 变量设置值?
    • 您可以在 Payload 中添加一个抽象方法,并在 PayloadA 和 PayloadB 中覆盖它,而不是 instanceof。然后,您可以从进程中调用此类方法,并使用正确的实现。
    • @RobertoAttias 你能提供一个例子,以便我能更好地理解。我对它的工作原理有点困惑。
    • @david 正如我在上面的代码中提到的,根据传递的对象,key 将被设置,所以你根本不需要使用instanceof 检查。
    • @javaguy 展示一个Payload 类的例子可能会有所帮助?
    【解决方案2】:
    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 中的调用。这被称为动态调度,因为在运行时调用哪个实现是已知的,而不是在编译时知道

    【讨论】:

    • 虽然您的代码对于任何熟悉 OOP 的人来说似乎都非常简单,但 OP 在多态性的概念上似乎并不强。您应该添加支持文本来解释您在做什么以及为什么要这样做。
    【解决方案3】:
    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();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多