这是在真实软件环境中制作构建器模式的正确方法吗?简而言之,在Java中创建构建器模式的最佳方法是什么

时间:2019-06-12 05:49:49

标签: java builder-pattern

这是在Java中创建构建器模式的正确方法,如果不能的话,可能会进行更改。

尝试使用静态类


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类制作对象

private Multiverse() {
          throw new IllegalStateException("Can`t create object from constructor: try using builder");

    }

预期与实际相同。但不确定这是否是实现目标的最佳方法。请对此进行更正或提出建议,[需要专家建议]

3 个答案:

答案 0 :(得分:1)

设计注意事项:

  • 强制使用构建器(不允许直接创建实例)?
  • 不变性(在创建实例后在构建器上调用setter时会发生什么情况?)?
  • 可重用性:是否允许构建器创建多个实例?

不可重用的构建器示例,可用于创建完全一个实例,该实例实际上是不可变的

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

答案 1 :(得分:0)

关于您的方法的一些说明:

  • 我认为“阻止”用户通过反射创建实例没有任何意义。由于定义了构造函数,因此始终没有no-arg构造函数。因此,只能通过传递构建器来创建实例。
  • 我喜欢将构建器实例传递给构造器。这样,即使类具有很多字段,您也将拥有可读的代码。
  • 我想称我的建设者为Builder。这是一个嵌套的类,您可能总是会写Multiverse.Builder
  • 我希望实际的类为构建器提供一个工厂方法,因此我只需编写Multiverse.builder()并开始填充字段即可。
  • builder类的方法应具有一致的命名方案。

这是我的建造者通常的样子:

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;

答案 2 :(得分:0)

这是我认为的最终解决方案,谢谢#stevecross

公共最终类BootServer {//步骤1使类和字段最终确定

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 + "]";
}

}