草庐IT

java - Java Bean 类的缺点是什么?

coder 2024-03-16 原文

我从Effective Java这本书中阅读了下面提到的这两个声明

第一名

Unfortunately, the JavaBeans pattern has serious disadvantages of its own. Because construction is split across multiple calls, a JavaBean may be in an inconsistent state partway through its construction.The class does not have the option of enforcing consistency merely by checking the validity of the constructor parameters. Attempting to use an object when it’s in an inconsistent state may cause failures that are far removed from the code containing the bug, hence difficult to debug.

第二名

A related disadvantage is that the JavaBeans pattern precludes the possibility of making a class immutable (Item 15), and requires added effort on the part of the programmer to ensure thread safety. It is possible to reduce these disadvantages by manually “freezing” the object when its construction is complete and not allowing it to be used until frozen, but this variant is unwieldy and rarely used in practice. Moreover, it can cause errors at runtime, as the compiler cannot ensure that the programmer calls the freeze method on an object before using it.

,我无法理解这两个语句到底想表达什么,你们能帮我理解上面的语句吗。

更新

我已经阅读了这篇文章的答案(不是全部),大多数社区成员建议我使用 Constructor Pattern 但在同一本书中这些行已经说过

Static factories and constructors share a limitation: they do not scale well to large numbers of optional parameters. Consider the case of a class representing the Nutrition Facts label that appears on packaged foods. These labels have a few required fields—serving size, servings per container, and calories per serving— and over twenty optional fields—total fat, saturated fat, trans fat, cholesterol, sodium, and so on. Most products have nonzero values for only a few of these optional fields.

对于这个场景,我们使用 telescoping constructor模式但是

The telescoping constructor pattern works, but it is hard to write client code when there are many parameters, and harder still to read it.The reader is left wondering what all those values mean and must carefully count parameters to find out. Long sequences of identically typed parameters can cause subtle bugs. If the client accidentally reverses two such parameters, the compiler won’t complain, but the program will misbehave at runtime

这就是为什么建议使用 JavaBeans 而不是 constructor pattern

最佳答案

让我们看看最简单的 Java Bean:

class Person {
   private String firstName;
   private String lastName;
   public String getFirstName() {return firstName;}
   public void setFirstName(String firstName) {this.firstName = firstName;}
   public String getLastName() {return lastName;}
   public void setLastName(String lastName) {this.lastName = lastName;}
}

以下代码创建 Person 的实例并启动它:

Person president = new Person();
p.setFirstName("George");
p.setLastName("Bush");

如你所见:

  1. 初始化确实分为 3 行。这意味着当所有 3 行都完成时对象处于恒定状态,而在此之前处于不一致状态。
    1. 该对象确实是可变的:它调用的值可以通过调用 setter 来更改。

为什么会这样?因为我们的类 Person 不是线程安全的,因此我们不能在不考虑同步的情况下直接在多线程环境中使用它。

这是一个例子。几年前,巴拉克奥巴马成为美国总统。我们如何用代码表达这一点?

p.setFirstName("Barak");
p.setLastName("Obama");

在多线程环境中,当 setFristName() 已完成且 setLastName() 尚未调用时,president 对象处于错误状态然而,因为该对象包含“Barak Bush”,这显然是错误的。

解决方案是什么?让我们让 Person 不可变:

class Person {
   private final String firstName;
   private final String lastName;
   Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
   }

   public String getFirstName() {return firstName;}
   public String getLastName() {return lastName;}
}

如您所见,无法更改对象中存储的名字或姓氏。字段是 final 并且没有 setter。因此,我们的示例如下所示:

Person president = new Person("George", "Bush"); //选举..... president = new Person("巴拉克", "奥巴马");

由于 Person 是不可变的,我们不能重新使用 Person 的旧实例并更改其属性。我们必须改为创建新实例。如果 presidentvolatitle 引用分配是原子的,因此代码是线程安全的。

更新

构造函数的问题在于它们不灵活。我们的示例只有 2 个参数。但想想现实世界中 Person 类可能有 20 个或更多字段。在这种情况下,创建此类对象非常冗长。

此外,有些字段可以是可选的。在这种情况下,您可能希望创建多个具有不同数量参数的重载构造函数。为了避免重复赋值代码,使用所谓的伸缩构造函数是常见的技术,即当构造函数调用其他构造函数时的模式。这种模式很好,但有些过于冗长且难以修改。

这只是意味着没有理想的解决方案。每种解决方案都有自己的优点和缺点。

顺便说一句,将不可变对象(immutable对象)的优点与对象创建和初始化的灵 active 相结合的解决方案是构建器模式。

我不会写出更好地理解这些问题所需的所有示例。但我希望我的回答对你有所帮助。现在您有了一个起点,可以使用其他资源了解这个问题。祝你好运。

关于java - Java Bean 类的缺点是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28394127/

有关java - Java Bean 类的缺点是什么?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  5. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  6. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

  7. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  8. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  9. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

  10. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

随机推荐