如何子class一个Java建设者class?
How to subclass a Java builder class?
我有两个生成器 - PayloadA
和 PayloadB
。为了使示例更简单,我删除了很多其他字段。
PayloadA.Builder
构造函数将 processName
、genericRecord
作为输入参数,然后从 genericRecord
中提取一些东西。我正在做验证。
PayloadB.Builder
构造函数也将 processName
、genericRecord
作为输入参数,然后它从 genericRecord
中提取了一些与上面不同的东西。在那些不同的领域,我正在做验证。
如您所见,这两个 Payload?.Builder
之间的共同点是 processName
、genericRecord
、提取 oldTimestamp
值然后 isValid
方法。
下面是我的PayloadA
class:
public final class PayloadA {
private final String clientId;
private final String deviceId;
private final String processName;
private final GenericRecord genericRecord;
private final Long oldTimestamp;
private PayloadA(Builder builder) {
this.clientId = builder.clientId;
this.deviceId = builder.deviceId;
this.processName = builder.processName;
this.genericRecord = builder.genericRecord;
this.oldTimestamp = builder.oldTimestamp;
}
public static class Builder {
private final String processName;
private final GenericRecord genericRecord;
private final String clientId;
private final String deviceId;
private final Long oldTimestamp;
public Builder(PayloadA payload) {
this.processName = payload.processName;
this.genericRecord = payload.genericRecord;
this.clientId = payload.clientId;
this.deviceId = payload.deviceId;
this.oldTimestamp = payload.oldTimestamp;
}
public Builder(String processName, GenericRecord genericRecord) {
this.processName = processName;
this.genericRecord = genericRecord;
this.clientId = (String) DataUtils.parse(genericRecord, "clientId");
this.deviceId = (String) DataUtils.parse(genericRecord, "deviceId");
this.oldTimestamp = (Long) DataUtils.parse(genericRecord, "oldTimestamp");
}
// calling this method to validate
public boolean isValid() {
return isValidClientIdDeviceId();
}
private boolean isValidClientIdDeviceId() {
// validate here
}
public PayloadA build() {
return new PayloadA(this);
}
}
// getter here
}
下面是我的PayloadB
class:
public final class PayloadB {
private final GenericRecord genericRecord;
private final String processName;
private final String type;
private final String datumId;
private final Long oldTimestamp;
private PayloadB(Builder builder) {
this.processName = builder.processName;
this.genericRecord = builder.genericRecord;
this.type = builder.type;
this.datumId = builder.datumId;
this.oldTimestamp = builder.oldTimestamp;
}
public static class Builder {
private final GenericRecord genericRecord;
private final String processName;
private final String type;
private final String datumId;
private final Long oldTimestamp;
public Builder(PayloadB payload) {
this.processName = payload.processName;
this.genericRecord = payload.genericRecord;
this.type = payload.type;
this.datumId = payload.datumId;
this.oldTimestamp = payload.oldTimestamp;
}
public Builder(String processName, GenericRecord genericRecord) {
this.processName = processName;
this.genericRecord = genericRecord;
this.type = (String) DataUtils.parse(genericRecord, "type");
this.datumId = (String) DataUtils.parse(genericRecord, "datumId");
this.oldTimestamp = (Long) DataUtils.parse(genericRecord, "oldTimestamp");
}
// calling this method to validate
public boolean isValid() {
return isValidType() && isValidDatumId();
}
private boolean isValidType() {
// validate here
}
private boolean isValidDatumId() {
// validate here
}
public PayloadB build() {
return new PayloadB(this);
}
}
// getter here
}
现在有什么方法可以在这里使用抽象概念 class 吗?我可以创建一个摘要 class Payload
但我的摘要 class:
中应该包含哪些内容
public final class PayloadA extends Payload { ... }
public final class PayloadB extends Payload { ... }
然后,一旦我构建了两个构建器,我会将其传递给其他方法,然后我想使用 getter 访问所有字段。所以假设我已经构建了 PayloadA
,所以我将发送到执行方法,如下所示,然后在该方法中,我想提取 PayloadA
的所有字段。同样,如果我将 PayloadB
发送到执行方法,那么我想使用 getter 提取 PayloadB
class 的所有字段。我该怎么做?
private void execute(Payload payload) {
// How can I access fields of PayloadA or PayloadB
// depending on what was passe
}
仅当上述字段碰巧不常见时,才为有效负载创建一个超级 class。您可以在其中移动公共字段和方法(但不能移动构建器)。您甚至可以为构建器创建一个超级 class,但它可能会使代码过于混乱。
如果您真的需要有效负载 super class,那么您可以使用 Visitor Pattern:
实现您的 execute
方法
首先,您必须创建一个访问者,您可以在其中访问您的具体 classes:
public class PayloadVisitor {
public void visit(PayloadA payloadA) {
// use payload A here
}
public void visit(PayloadB payloadB) {
// use payload B here
}
}
然后你必须添加一个方法到你的超级class接受访问者:
public abstract class Payload {
// common fields and methods
public abstract void accept(PayloadVisitor visitor);
}
覆盖子class中的方法accept
:
public final class PayloadA extends Payload {
// ...
@Override
public void accept(PayloadVisitor visitor) {
visitor.visit(this);
}
}
public final class PayloadB extends Payload {
// ...
@Override
public void accept(PayloadVisitor visitor) {
visitor.visit(this);
}
}
您的方法 execute
只是将调用重定向到相应的 visit
方法:
private void execute(Payload payload) {
payload.accept(new PayloadVisitor());
}
访客模式可能会让人不知所措。也可以简单点,用instanceof
来确定具体的class.
我认为这里的问题是 PayloadA 和 PayloadB 是否在设计中共享一些意义完整的东西。如果除了一个参数之外逻辑在某种程度上是相同的,那么你可以有一个 class.
也许你可以有抽象class,对于特定领域的实现你可以return你对特定实现的具体值。
例如 Abstract class 有一个字段的抽象 setter/getter ,当您将该方法实现到 PayloadA 和 PayloadB 时,您可以 return 您想要的字段。
我认为问题是这里的设计而不是如何去做。看看你的 class 是什么,然后你有很多选择
我有两个生成器 - PayloadA
和 PayloadB
。为了使示例更简单,我删除了很多其他字段。
PayloadA.Builder
构造函数将processName
、genericRecord
作为输入参数,然后从genericRecord
中提取一些东西。我正在做验证。PayloadB.Builder
构造函数也将processName
、genericRecord
作为输入参数,然后它从genericRecord
中提取了一些与上面不同的东西。在那些不同的领域,我正在做验证。
如您所见,这两个 Payload?.Builder
之间的共同点是 processName
、genericRecord
、提取 oldTimestamp
值然后 isValid
方法。
下面是我的PayloadA
class:
public final class PayloadA {
private final String clientId;
private final String deviceId;
private final String processName;
private final GenericRecord genericRecord;
private final Long oldTimestamp;
private PayloadA(Builder builder) {
this.clientId = builder.clientId;
this.deviceId = builder.deviceId;
this.processName = builder.processName;
this.genericRecord = builder.genericRecord;
this.oldTimestamp = builder.oldTimestamp;
}
public static class Builder {
private final String processName;
private final GenericRecord genericRecord;
private final String clientId;
private final String deviceId;
private final Long oldTimestamp;
public Builder(PayloadA payload) {
this.processName = payload.processName;
this.genericRecord = payload.genericRecord;
this.clientId = payload.clientId;
this.deviceId = payload.deviceId;
this.oldTimestamp = payload.oldTimestamp;
}
public Builder(String processName, GenericRecord genericRecord) {
this.processName = processName;
this.genericRecord = genericRecord;
this.clientId = (String) DataUtils.parse(genericRecord, "clientId");
this.deviceId = (String) DataUtils.parse(genericRecord, "deviceId");
this.oldTimestamp = (Long) DataUtils.parse(genericRecord, "oldTimestamp");
}
// calling this method to validate
public boolean isValid() {
return isValidClientIdDeviceId();
}
private boolean isValidClientIdDeviceId() {
// validate here
}
public PayloadA build() {
return new PayloadA(this);
}
}
// getter here
}
下面是我的PayloadB
class:
public final class PayloadB {
private final GenericRecord genericRecord;
private final String processName;
private final String type;
private final String datumId;
private final Long oldTimestamp;
private PayloadB(Builder builder) {
this.processName = builder.processName;
this.genericRecord = builder.genericRecord;
this.type = builder.type;
this.datumId = builder.datumId;
this.oldTimestamp = builder.oldTimestamp;
}
public static class Builder {
private final GenericRecord genericRecord;
private final String processName;
private final String type;
private final String datumId;
private final Long oldTimestamp;
public Builder(PayloadB payload) {
this.processName = payload.processName;
this.genericRecord = payload.genericRecord;
this.type = payload.type;
this.datumId = payload.datumId;
this.oldTimestamp = payload.oldTimestamp;
}
public Builder(String processName, GenericRecord genericRecord) {
this.processName = processName;
this.genericRecord = genericRecord;
this.type = (String) DataUtils.parse(genericRecord, "type");
this.datumId = (String) DataUtils.parse(genericRecord, "datumId");
this.oldTimestamp = (Long) DataUtils.parse(genericRecord, "oldTimestamp");
}
// calling this method to validate
public boolean isValid() {
return isValidType() && isValidDatumId();
}
private boolean isValidType() {
// validate here
}
private boolean isValidDatumId() {
// validate here
}
public PayloadB build() {
return new PayloadB(this);
}
}
// getter here
}
现在有什么方法可以在这里使用抽象概念 class 吗?我可以创建一个摘要 class Payload
但我的摘要 class:
public final class PayloadA extends Payload { ... }
public final class PayloadB extends Payload { ... }
然后,一旦我构建了两个构建器,我会将其传递给其他方法,然后我想使用 getter 访问所有字段。所以假设我已经构建了 PayloadA
,所以我将发送到执行方法,如下所示,然后在该方法中,我想提取 PayloadA
的所有字段。同样,如果我将 PayloadB
发送到执行方法,那么我想使用 getter 提取 PayloadB
class 的所有字段。我该怎么做?
private void execute(Payload payload) {
// How can I access fields of PayloadA or PayloadB
// depending on what was passe
}
仅当上述字段碰巧不常见时,才为有效负载创建一个超级 class。您可以在其中移动公共字段和方法(但不能移动构建器)。您甚至可以为构建器创建一个超级 class,但它可能会使代码过于混乱。
如果您真的需要有效负载 super class,那么您可以使用 Visitor Pattern:
实现您的execute
方法
首先,您必须创建一个访问者,您可以在其中访问您的具体 classes:
public class PayloadVisitor {
public void visit(PayloadA payloadA) {
// use payload A here
}
public void visit(PayloadB payloadB) {
// use payload B here
}
}
然后你必须添加一个方法到你的超级class接受访问者:
public abstract class Payload {
// common fields and methods
public abstract void accept(PayloadVisitor visitor);
}
覆盖子class中的方法accept
:
public final class PayloadA extends Payload {
// ...
@Override
public void accept(PayloadVisitor visitor) {
visitor.visit(this);
}
}
public final class PayloadB extends Payload {
// ...
@Override
public void accept(PayloadVisitor visitor) {
visitor.visit(this);
}
}
您的方法 execute
只是将调用重定向到相应的 visit
方法:
private void execute(Payload payload) {
payload.accept(new PayloadVisitor());
}
访客模式可能会让人不知所措。也可以简单点,用instanceof
来确定具体的class.
我认为这里的问题是 PayloadA 和 PayloadB 是否在设计中共享一些意义完整的东西。如果除了一个参数之外逻辑在某种程度上是相同的,那么你可以有一个 class.
也许你可以有抽象class,对于特定领域的实现你可以return你对特定实现的具体值。
例如 Abstract class 有一个字段的抽象 setter/getter ,当您将该方法实现到 PayloadA 和 PayloadB 时,您可以 return 您想要的字段。
我认为问题是这里的设计而不是如何去做。看看你的 class 是什么,然后你有很多选择