【问题标题】:Java Model Objects designJava 模型对象设计
【发布时间】:2013-05-09 09:02:34
【问题描述】:

所以我一直在阅读一些Effective Java!书中最鼓舞人心的部分之一是不可变对象/构建器部分,布洛赫在其中写了“构建器”——类,而不仅仅是 POJO。

注意:我在这里谈论的是模型对象:例如 ArticleCar

这就是我之前写这些对象的方式:

public class Car {

     private String name;

     public void setName(String name) {
         this.name = name;
     }

     public String getName() {
         return name;
     }
}

现在你看到这个设计在很多方面都有缺陷,它需要可变性,你必须先用构造函数构造对象,然后设置名称。

现在你当然可以将 name 字段设为 final 并将其用作构造函数中的参数,但是如果你有一个大对象包装例如一些 SQL - 表,那么你将有一个丑陋的构造函数,像这样:

public Car(int horsepowers, String name, String brand, int yearManufactured,
    User owner, List<User> previousOwners) {
    //Set the values
}

这在创建对象时变得不可读,而这只是六个字段!

因此,布洛赫提出以下建议(具有不变性)

public class Car {

     public static class Builder {

         private String name;

         public Builder setName(String name) {
             this.name = name;
             return this;
         }

         public Car build() {
             reeturn new Car(this);
         }
     }

     private final String name;

     private Car(Builder builder) {
         name = builder.name;
     }

     public String getName() {
         return name;
     }
}

//Construction example
Car car = new Car.Builder().setName("Speedy").build();

现在这给了我们不变性!如果您有一些对象不是原始的或不可变的,只需将它们复制到 Builder 的设置器中,然后再次将它们复制到 Car 的获取器中。

但它非常罗嗦,如果类足够小,我一直在使用构造函数参数。 如果一个类需要一个可变字段,如果该类有足够的属性(> 4 个),我只需将该字段设为可变。

另一个问题是,当使用 android 并且该类具有例如 Bitmap 时,您必须返回实际位图而不是复制它,因为这相当性能 - 昂贵。

我见过很多这样的问题,但我似乎无法找到一个很好的答案:这些设计是否有任何标准?它们的设计如何?有什么好处/缺点?

提前致谢!

编辑:

问题是:

构造一个应该是不可变的对象模型的最佳方法是什么?A)少量字段和B)大量字段?如何处理上述Bitmap 问题和类似问题?使某些字段可变?

抱歉含糊了。

【问题讨论】:

  • 我认为Builder 的重点是当您处理具有一些必需和可选字段的不可变对象时。因为您将字段声明为final。所以它并不适用于所有设计。

标签: java object model effective-java


【解决方案1】:

Design Patterns 这本书是目前设计模式的 alpha 和 omega。不过它并不新鲜,但它似乎通过了时间的考验。

您可以阅读每种设计模式的详细真实示例、它们之间的关系、如何以及何时使用它们以及对每种设计模式的详尽解释。 Builder 模式当然也包括在内。

至于回答你的问题,我可以发表我的观点,虽然它们当然不是权威的。

我认为如果你有少量的字段,你可以使用构造函数。如果你以checkstyle 为例,它会触发超过 7 个参数的警告。

但是,如果您确定您将很快重构该类,或者您将不得不扩展它,我认为 Builder 模式更好,因为它更容易重构。重构构造函数从来都不是一件有趣的事。

如果您超过 7 个参数,我认为 Builder 会好得多。我一直在我正在广泛开展的当前项目中使用它。

请注意,通过使用构建器模式,您不会说“好吧,我是一个不可变的对象构建器”。你说“好的,我正在构建参数化对象”。因此,您的类中有一组可变字段不是问题。但是,如果您将类命名为 ImmutableFooDTO,然后添加可变字段,则会导致混淆。

因此,如果有一组字段不能是可变的,则将它们标记为 final 并使用构造函数/构建器并为可变字段提供设置器。

【讨论】:

  • 嗨!是的,我已经阅读了 Java 等价物,但那是构建器模式,正如您所见,它的限制较少。它并没有真正回答这个问题。不过感谢您的回复。
  • 请再看看你的问题:“这些设计有什么标准吗?它们的设计如何?有什么好处/缺点?”我已经回答了你的问题。我在那里看不到任何其他问号。
  • 您好,我知道这个问题,感谢您的回复。但这里的问题是 何时 使用哪个模型:上面解释的 Builder 或构造函数参数,如何处理不可变/可变字段等。我不能仅仅因为你链接到一本本身是工业“标准”的书,但仍然没有涵盖我在这里的评论和上面的问题中提到的所有方面。
  • 我认为要么我的理解不完善,要么你的问题有点模糊。我没有看到您的问题到底在哪里。你说的事情然后为他们提供了解决方案。究竟是什么问题?
  • 我会更新问题,是的,我猜这个问题有点含糊,谢谢指出。
【解决方案2】:

我将其作为“答案”输入,因此我有空间解释,但这实际上只是对 Adam Aroid 发起的线程的评论。

Johan,首先我假设您是在谈论 Effective Java 中的第 2 条。

请注意,这里呈现的是 Adam Aroid 提到的 Builder 模式的一种形式。 Josh Bloch 在 Effective Java 中展示代码之前就直接提到了这一点:“它是 Builder 模式的一种形式 [Gamma95, p. 97]。” (那是在第 13 页。)他后来提到了一种使用另一种模式的方法(来自同一本书):“已设置参数的构建器制造了一个很好的抽象工厂 [Gamma95, p. 87]。

Johan,您提出的问题对于此处的空间而言过于宽泛。我认为最好的答案是 Adam Aroid 的答案。这需要一些研究,然后应用该研究来获得一些经验。 《设计模式》一书中的讨论极大地促进了这一点。我会投票给亚当的答案。

【讨论】:

    【解决方案3】:

    试试这个代码:

     public static boolean isEmailValid(String email) {
    
        boolean isValid = false;
    
        String expression = "^[\\w\\.-]+@([\\w\\-]+\\.)+[A-Z]{2,4}$";
        CharSequence inputStr = email;
    
        Pattern pattern = Pattern.compile(expression, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(inputStr);
        if (matcher.matches()) {
            isValid = true;
        }
        return isValid;
    }
    

    【讨论】:

    • 您的回答是否与帖子所有者的问题有关?请帮助 Stackoverflow 为开发者维护好的内容。
    猜你喜欢
    • 2012-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多