这是在真实软件环境中制作构建器模式的正确方法吗?简而言之,在 java 中创建构建器模式的最佳方式是什么
is this the right way to make builder pattern in real software environment? in short what is the best way to create builder pattern in java
这是在 java 中创建构建器模式的正确方法吗?如果不是,可以进行哪些更改。
尝试使用静态 class
public class Multiverse {
private UUID universeId;
private String universeName;
private String universeType;
private Boolean humanExistence;
public Boolean getHumanExistence() {
return humanExistence;
}
private Multiverse() {
throw new IllegalStateException("Can`t create object from constructor: try using builder");
}
private Multiverse(UUID universeId, String universeName, String universeType, Boolean humanExistence) {
super();
this.universeId = universeId;
this.universeName = universeName;
this.universeType = universeType;
this.humanExistence = humanExistence;
}
public static class MultiverseBuilder{
private UUID universeId;
private String universeName;
private String universeType;
private Boolean humanExistence;
public MultiverseBuilder makeUUId(UUID uuid) {
this.universeId=uuid;
return this;
}
public MultiverseBuilder createUniverse(String univ) {
this.universeName=univ;
return this;
}
public MultiverseBuilder setUniverseType(String universeType ) {
this.universeType=universeType;
return this;
}
public MultiverseBuilder isHumanExists(Boolean humanExistence) {
this.humanExistence=humanExistence;
return this;
}
public Multiverse build() {
return new Multiverse(universeId,universeName,universeType,humanExistence);
}
}
public UUID getUniverseId() {
return universeId;
}
public String getUniverseName() {
return universeName;
}
public String getUniverseType() {
return universeType;
}
}
Junit5测试
public class AssertionsTest6 {
private static Logger logger=Logger.getLogger(AssertionsTest6.class.getName());
Multiverse multiverse;
@BeforeEach
void init(){
multiverse=new Multiverse.MultiverseBuilder()
.makeUUId(UUID.randomUUID())
.createUniverse("Earth")
.setUniverseType("Big Bang")
.isHumanExists(true)
.build();
}
@Test
@DisplayName("Builder Testing")
void TestBuilder() {
assertEquals("Big Bang", multiverse.getUniverseType(), "test failed");
logger.info("Builder testing");
}
}
阻止反射直接从 Multiverse class 这样做
private Multiverse() {
throw new IllegalStateException("Can`t create object from constructor: try using builder");
}
预期和实际相同。但不确定这是实现 objective 的最佳方法。请纠正或建议我,[需要专家建议]
关于您的方法的一些说明:
- 我认为 'block' 用户通过反射创建实例没有任何意义。由于您定义了构造函数,因此无论如何都没有 no-arg 构造函数。因此实例只能通过传递一个构建器来创建。
- 我喜欢将构建器实例传递给构造函数。这样,即使 class 有很多字段,您也将拥有可读的代码。
- 我喜欢直接称呼我的建筑商
Builder
。这是一个嵌套的 class,你可能总是写 Multiverse.Builder
.
- 我喜欢实际的 class 为构建器提供工厂方法,这样我就可以编写
Multiverse.builder()
并开始填充字段。
- 构建器的方法 class 应该具有一致的命名方案。
我的建筑工人通常是这样的:
public class Multiverse {
private final UUID universeId;
private final String universeName;
private final String universeType;
private final Boolean humanExistence;
private Multiverse(Builder builder) {
this.universeId = builder.universeId;
this.universeName = builder.universeName;
this.universeType = builder.universeType;
this.humanExistence = builder.humanExistence;
}
public static Builder builder() {
return new Builder();
}
public UUID getUniverseId() {
return universeId;
}
public String getUniverseName() {
return universeName;
}
public String getUniverseType() {
return universeType;
}
public Boolean getHumanExistence() {
return humanExistence;
}
public Builder toBuilder() {
return new Builder(this);
}
public static class Builder {
private UUID universeId;
private String universeName;
private String universeType;
private Boolean humanExistence;
private Builder() {}
private Builder(Multiverse multiverse) {
this.universeId = multiverse.universeId;
this.universeName = multiverse.universeName;
this.universeType = multiverse.universeType;
this.humanExistence = multiverse.humanExistence;
}
public Builder withUniverseId(UUID universeId) {
this.universeId = universeId;
return this;
}
public Builder withUniverseName(String universeName) {
this.universeName = universeName;
return this;
}
public Builder withUniverseType(String universeType) {
this.universeType = universeType;
return this;
}
public Builder withHumanExistence(Boolean humanExistence) {
this.humanExistence = humanExistence;
return this;
}
public Multiverse build() {
return new Multiverse(this);
}
}
}
创建多重宇宙的工作方式如下:
Multiverse multiverse1 = Multiverse.builder()
.withUniverseId(UUID.fromString("550e8400-e29b-11d4-a716-446655440000"))
.withUniverseName("my first multiverse")
.withUniverseType("type a")
.withHumanExistence(true)
.build();
如果您以后决定编辑这个多元宇宙,您可以这样做:
Multiverse multiverse2 = multiverse1.toBuilder()
.withUniverseId(UUID.fromString("759e947a-7492-af67-87bd-87de9e7f5e95"))
.withUniverseName("my second multiverse")
.build();
这将满足以下断言:
assert multiverse1.getUniverseId().equals("550e8400-e29b-11d4-a716-446655440000");
assert multiverse1.getUniverseName().equals("my first multiverse");
assert multiverse1.getUniverseType.equals("type a");
assert multiverse1.getHumanExistence == true;
assert multiverse2.getUniverseId().equals("759e947a-7492-af67-87bd-87de9e7f5e95");
assert multiverse2.getUniverseName().equals("my second multiverse");
assert multiverse2.getUniverseType.equals("type a");
assert multiverse2.getHumanExistence == true;
设计注意事项:
- 强制使用构建器(不允许直接创建实例)?
- 不变性(在创建实例后调用构建器上的 setter 会发生什么)?
- 可重用性:允许构建器创建多个实例?
non-reusable 构建器的示例,可用于创建 一个实例 ,它实际上是 不可变的 :
public class Multiverse {
private UUID universeId;
private String universeName;
private String universeType;
private Boolean humanExistence;
private Multiverse() {
}
public UUID getUniverseId() {
return universeId;
}
public String getUniverseName() {
return universeName;
}
public String getUniverseType() {
return universeType;
}
public Boolean getHumanExistence() {
return humanExistence;
}
public static Builder aMultiverse() {
return new Builder();
}
public static class Builder {
private final Multiverse instance = new Multiverse();
private boolean consumed;
private Builder set(Consumer<Multiverse> access) {
if (consumed) {
throw new IllegalStateException("already consumed");
}
access.accept(instance);
return this;
}
public Builder universeId(UUID universeId) {
return set(x -> x.universeId = universeId);
}
public Builder universeName(String universeName) {
return set(x -> x.universeName = universeName);
}
public Builder universeType(String universeType) {
return set(x -> x.universeType = universeType);
}
public Builder humanExistence(Boolean humanExistence) {
return set(x -> x.humanExistence = humanExistence);
}
public Multiverse build() {
consumed = true;
return instance;
}
}
}
用于访问构建器的 aMultiVerse()
命名约定允许静态导入构建器工厂方法,而不会与其他构建器工厂方法发生冲突:
Multiverse multiverse = aMultiverse()
.universeId(UUID.randomUUID())
.universeName("Earth")
.universeType("Big Bang")
.humanExistence(true)
.build();
这是我认为的最终解决方案,谢谢#stevecross
public final class BootServer { // 步骤 #1 生成 class 和字段 final
private final Integer port;
private final String serverName;
private final String serverType;
private final String listenerType;
private BootServer(Builder builder) {// step #2 create private constructor
this.port = builder.port;
this.serverName = builder.serverName;
this.serverType = builder.serverType;
this.listenerType=builder.listenerType;
}
public static Builder builder() {//Step#3 create static builder method to return Builder
return new Builder();
}
public static final class Builder {//Step#4 create public static builder class
private Integer port;
private String serverName;
private String serverType;
private String listenerType;
private Builder(){
}
public BootServer build() {//Step#5 create build method to return BootServer Object with this object
return new BootServer(this);
}
public Builder addServerPort(Integer port) {//Step#6 finally create all build method to set values to main class
this.port=port;
return this;
}
public Builder addServerName(String name) {
this.serverName=name;
return this;
}
public Builder setServerType(String serverType) {
this.serverType=serverType;
return this;
}
public Builder setListenerType(String listenerType) {
this.listenerType=listenerType;
return this;
}
}
@Override
public String toString() {
return "BootServer [port=" + port + ", serverName=" + serverName + ", serverType=" + serverType
+ ", listenerType=" + listenerType + "]";
}
}
这是在 java 中创建构建器模式的正确方法吗?如果不是,可以进行哪些更改。
尝试使用静态 class
public class Multiverse {
private UUID universeId;
private String universeName;
private String universeType;
private Boolean humanExistence;
public Boolean getHumanExistence() {
return humanExistence;
}
private Multiverse() {
throw new IllegalStateException("Can`t create object from constructor: try using builder");
}
private Multiverse(UUID universeId, String universeName, String universeType, Boolean humanExistence) {
super();
this.universeId = universeId;
this.universeName = universeName;
this.universeType = universeType;
this.humanExistence = humanExistence;
}
public static class MultiverseBuilder{
private UUID universeId;
private String universeName;
private String universeType;
private Boolean humanExistence;
public MultiverseBuilder makeUUId(UUID uuid) {
this.universeId=uuid;
return this;
}
public MultiverseBuilder createUniverse(String univ) {
this.universeName=univ;
return this;
}
public MultiverseBuilder setUniverseType(String universeType ) {
this.universeType=universeType;
return this;
}
public MultiverseBuilder isHumanExists(Boolean humanExistence) {
this.humanExistence=humanExistence;
return this;
}
public Multiverse build() {
return new Multiverse(universeId,universeName,universeType,humanExistence);
}
}
public UUID getUniverseId() {
return universeId;
}
public String getUniverseName() {
return universeName;
}
public String getUniverseType() {
return universeType;
}
}
Junit5测试
public class AssertionsTest6 {
private static Logger logger=Logger.getLogger(AssertionsTest6.class.getName());
Multiverse multiverse;
@BeforeEach
void init(){
multiverse=new Multiverse.MultiverseBuilder()
.makeUUId(UUID.randomUUID())
.createUniverse("Earth")
.setUniverseType("Big Bang")
.isHumanExists(true)
.build();
}
@Test
@DisplayName("Builder Testing")
void TestBuilder() {
assertEquals("Big Bang", multiverse.getUniverseType(), "test failed");
logger.info("Builder testing");
}
}
阻止反射直接从 Multiverse class 这样做
private Multiverse() {
throw new IllegalStateException("Can`t create object from constructor: try using builder");
}
预期和实际相同。但不确定这是实现 objective 的最佳方法。请纠正或建议我,[需要专家建议]
关于您的方法的一些说明:
- 我认为 'block' 用户通过反射创建实例没有任何意义。由于您定义了构造函数,因此无论如何都没有 no-arg 构造函数。因此实例只能通过传递一个构建器来创建。
- 我喜欢将构建器实例传递给构造函数。这样,即使 class 有很多字段,您也将拥有可读的代码。
- 我喜欢直接称呼我的建筑商
Builder
。这是一个嵌套的 class,你可能总是写Multiverse.Builder
. - 我喜欢实际的 class 为构建器提供工厂方法,这样我就可以编写
Multiverse.builder()
并开始填充字段。 - 构建器的方法 class 应该具有一致的命名方案。
我的建筑工人通常是这样的:
public class Multiverse {
private final UUID universeId;
private final String universeName;
private final String universeType;
private final Boolean humanExistence;
private Multiverse(Builder builder) {
this.universeId = builder.universeId;
this.universeName = builder.universeName;
this.universeType = builder.universeType;
this.humanExistence = builder.humanExistence;
}
public static Builder builder() {
return new Builder();
}
public UUID getUniverseId() {
return universeId;
}
public String getUniverseName() {
return universeName;
}
public String getUniverseType() {
return universeType;
}
public Boolean getHumanExistence() {
return humanExistence;
}
public Builder toBuilder() {
return new Builder(this);
}
public static class Builder {
private UUID universeId;
private String universeName;
private String universeType;
private Boolean humanExistence;
private Builder() {}
private Builder(Multiverse multiverse) {
this.universeId = multiverse.universeId;
this.universeName = multiverse.universeName;
this.universeType = multiverse.universeType;
this.humanExistence = multiverse.humanExistence;
}
public Builder withUniverseId(UUID universeId) {
this.universeId = universeId;
return this;
}
public Builder withUniverseName(String universeName) {
this.universeName = universeName;
return this;
}
public Builder withUniverseType(String universeType) {
this.universeType = universeType;
return this;
}
public Builder withHumanExistence(Boolean humanExistence) {
this.humanExistence = humanExistence;
return this;
}
public Multiverse build() {
return new Multiverse(this);
}
}
}
创建多重宇宙的工作方式如下:
Multiverse multiverse1 = Multiverse.builder()
.withUniverseId(UUID.fromString("550e8400-e29b-11d4-a716-446655440000"))
.withUniverseName("my first multiverse")
.withUniverseType("type a")
.withHumanExistence(true)
.build();
如果您以后决定编辑这个多元宇宙,您可以这样做:
Multiverse multiverse2 = multiverse1.toBuilder()
.withUniverseId(UUID.fromString("759e947a-7492-af67-87bd-87de9e7f5e95"))
.withUniverseName("my second multiverse")
.build();
这将满足以下断言:
assert multiverse1.getUniverseId().equals("550e8400-e29b-11d4-a716-446655440000");
assert multiverse1.getUniverseName().equals("my first multiverse");
assert multiverse1.getUniverseType.equals("type a");
assert multiverse1.getHumanExistence == true;
assert multiverse2.getUniverseId().equals("759e947a-7492-af67-87bd-87de9e7f5e95");
assert multiverse2.getUniverseName().equals("my second multiverse");
assert multiverse2.getUniverseType.equals("type a");
assert multiverse2.getHumanExistence == true;
设计注意事项:
- 强制使用构建器(不允许直接创建实例)?
- 不变性(在创建实例后调用构建器上的 setter 会发生什么)?
- 可重用性:允许构建器创建多个实例?
non-reusable 构建器的示例,可用于创建 一个实例 ,它实际上是 不可变的 :
public class Multiverse {
private UUID universeId;
private String universeName;
private String universeType;
private Boolean humanExistence;
private Multiverse() {
}
public UUID getUniverseId() {
return universeId;
}
public String getUniverseName() {
return universeName;
}
public String getUniverseType() {
return universeType;
}
public Boolean getHumanExistence() {
return humanExistence;
}
public static Builder aMultiverse() {
return new Builder();
}
public static class Builder {
private final Multiverse instance = new Multiverse();
private boolean consumed;
private Builder set(Consumer<Multiverse> access) {
if (consumed) {
throw new IllegalStateException("already consumed");
}
access.accept(instance);
return this;
}
public Builder universeId(UUID universeId) {
return set(x -> x.universeId = universeId);
}
public Builder universeName(String universeName) {
return set(x -> x.universeName = universeName);
}
public Builder universeType(String universeType) {
return set(x -> x.universeType = universeType);
}
public Builder humanExistence(Boolean humanExistence) {
return set(x -> x.humanExistence = humanExistence);
}
public Multiverse build() {
consumed = true;
return instance;
}
}
}
用于访问构建器的 aMultiVerse()
命名约定允许静态导入构建器工厂方法,而不会与其他构建器工厂方法发生冲突:
Multiverse multiverse = aMultiverse()
.universeId(UUID.randomUUID())
.universeName("Earth")
.universeType("Big Bang")
.humanExistence(true)
.build();
这是我认为的最终解决方案,谢谢#stevecross
public final class BootServer { // 步骤 #1 生成 class 和字段 final
private final Integer port;
private final String serverName;
private final String serverType;
private final String listenerType;
private BootServer(Builder builder) {// step #2 create private constructor
this.port = builder.port;
this.serverName = builder.serverName;
this.serverType = builder.serverType;
this.listenerType=builder.listenerType;
}
public static Builder builder() {//Step#3 create static builder method to return Builder
return new Builder();
}
public static final class Builder {//Step#4 create public static builder class
private Integer port;
private String serverName;
private String serverType;
private String listenerType;
private Builder(){
}
public BootServer build() {//Step#5 create build method to return BootServer Object with this object
return new BootServer(this);
}
public Builder addServerPort(Integer port) {//Step#6 finally create all build method to set values to main class
this.port=port;
return this;
}
public Builder addServerName(String name) {
this.serverName=name;
return this;
}
public Builder setServerType(String serverType) {
this.serverType=serverType;
return this;
}
public Builder setListenerType(String listenerType) {
this.listenerType=listenerType;
return this;
}
}
@Override
public String toString() {
return "BootServer [port=" + port + ", serverName=" + serverName + ", serverType=" + serverType
+ ", listenerType=" + listenerType + "]";
}
}