繁体   English   中英

在构建器模式中将抽象类子类化?

[英]Subclassing abstract class in a builder pattern?

我有两种类型的有效负载来自上游: 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);
    }
  }

并在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方法的Payload类中设置createTimestampkey变量? 现在,我有一个区分的运行方法,但是通常我将为PayloadA使用不同的上游代码,为PayloadB使用不同的上游代码,因此我们将使用其中一个Payload类。

另外,我应该在这里安排两名不同的建筑商,还是在这里一名大型建筑商?

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

如何确定有效载荷是process()内的PayloadA还是PayloadB

您可以发现使用instanceof就像上面所示的PayloadA payload instanceof一样。 但是,通常来说,使用instanceof检查进行编码不是一个好主意,因此除非无法避免,否则不要使用它。

我应该在这里安排两名不同的建设者,还是在其中一名大型建设者?

根据上面提供的代码,这些字段的PayloadAPayloadB不同,因此最好保留单独的bean和相应的构建器。

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

里面setKey()将调用传递给对象类型process(Payload payload) (多态性的OOP的基本原则之一),即,如果传递PayloadA从对象run()方法, setKey()PayloadA对象将叫做。 总而言之,您根本不需要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();
}

编辑

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

现在假设你做

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM