java - 在正确的地方使用正确的构建器

标签 java multithreading design-patterns builder qa

我对构建器模式非常感兴趣,我经常使用它,但我不确定我制作的构建器是否足够好,而且我对可以使用它们的所有环境也有疑问。
这是我如何创建构建器的示例:

public class Person {

    private String name;
    private String secondName;
    private int age;

    public static class Builder {
        private boolean isBuilt;
        private Person person = new Person();

        private void check() {
            if (isBuilt) {
                throw new IllegalStateException(
                        "The object cannot be modified after built");
            }
        }

        public Builder withName(String name) {
            check();
            person.name = name;
            return this;
        }

        public Builder withSecondName(String secondName) {
            check();
            person.secondName = secondName;
            return this;
        }

        public Builder withAge(int age) {
            check();
            person.age = age;
            return this;
        }

        public Person build() {
            check();
            isBuilt = true;
            return person;
        }
    }

    @Override
    public String toString() {
        return "Name: " + name + "\nSecond name:" + secondName + "\nAge:" + age;
    }
}

只是一个快速使用示例:
Person person = new Person.Builder()
        .withName("John")
        .withSecondName("Smith")
        .withAge(50)
        .build();
        System.out.println(person);

以下是我的一些疑惑:
  • 你认为它真的是一成不变的吗?如果不是,我该如何改进?
  • 关于线程安全。嗯,这可能是我的主要疑问。这真的是线程安全的吗?
    我在互联网上看到一些例子,说类级别的变量必须是最终的并通过构造函数传递。我还看到了一个例子,其中变量被声明为 volatile。你怎么看待这件事?
  • 您认为这个构建器在可以使用的场景方面有什么限制吗?我的意思是它适合在 EJB、JSF 支持 bean、MDB 中调用还是适合成为 JPA 实体......?
  • 最佳答案

    Do you think it is really immutable? [...] Is this really thread safe?



    您的代码的任何部分都不是一成不变的。这也可能会妨碍线程安全;也就是说,很难以二进制方式声明一个类是否是线程安全的。我也不明白为什么你会首先在线程之间共享构建器实例,但我可能会被你的代码示例的简单性所误导。

    为了更轻松地实现线程安全,您的 Builder s 本身应该是不可变的。这意味着每个 withXXX()方法应该返回一个代表新状态的新构建器。 (可能有更聪明的方法可以做到这一点,但这将是最直接的方法。)

    只是重申一下:我不确定是否有必要使构建器线程安全 - 大多数情况下它们是生命周期和可见范围非常短的对象。您是否想让它们不可变取决于用例,您可能想要存储部分填充的构建器,但这也很少见。 (但主观上,名称以 with 开头的方法似乎更直观,而不是就地修改对象,而不是名称以 set 开头的方法。)

    Do you think that this builder would have any limitation in what regards the scenario where it can be used?



    这通常是无法回答的,但如果你确实让你的 Person对象不可变,因此只能由您的构建器构建,它们将无法用作 JPA 实体,我的猜测也是作为 JSF 支持 bean。为您创建/管理某些对象的 Java 框架通常不希望它们是 JavaBean,这意味着可以通过反射调用无参数构造函数和属性 setter 来创建这些对象。

    关于java - 在正确的地方使用正确的构建器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14803844/

    相关文章:

    c# - 界面及其可访问性

    design-patterns - 规范模式、Func<T,bool> 谓词与管道和过滤器的比较

    .net - View 和 ViewModel 之间的 MVVM 依赖关系

    java - 如何打印第一个余额,然后打印新余额?

    java - 在 Java 中的另一个数据映射器中使用数据映射器?

    Java AWS SDK v2 : List bucket keys, 但仅限文件

    c# - 在 c# 控制台应用程序中的 2 个线程之间传递变量(这里是新手)

    .net - 在 .NET 中通过 Process.Start 生成的进程会挂起线程

    java ssl tcp 连接正常,但接收到服务器的数据不正确

    c++ - 2个线程比1个慢?