Java Beans作为数据存储类设计不好吗?

The*_*eLQ 11 java javabeans

通常JavaPractices.com是一个好主意的好网站,但这个让我烦恼:JavaBeans很糟糕.

本文引用了几个原因,主要是JavaBean这个术语的意思是"Java Bean是一个可重用的软件组件,可以在构建器工具中以可视方式进行操作".不是数据存储,违反了某些模式,而且更复杂.

现在我同意最后一个,但在我看来,列表中的JavaBeans比嵌套的地图更有意义.文章声称数据库映射框架应该调用构造函数,而不是set*方法,并且对象应该是不可变的.但是在我看来,在尝试构建对象时调用set*方法比阅读更容易new MappedObject("column1", "column2", "yet another column", "this is stupid");

除了数据库映射之外,我还使用JavaBean样式类进行其他操作,例如对于IRC bot,每个用户都有一个对象,可以使用各种内容进行更新.每次给出新信息时我都不想创建新对象,我想将其添加到现有对象中.

所以我的问题是:使用JavaBeans进行数据存储是一种不好的做法,应该避免,还是非常安全?

Osc*_*Ryz 20

你似乎在误读文本.

现在我同意最后一个,但在我看来,列表中的JavaBeans比嵌套映射更有意义

该文本从未提及嵌套地图作为替代(yiack)

...应该调用构造函数,而不是设置*方法,并且对象应该是不可变的

这是一个很好的做法,在处理线程时特别有用.

但我们不能说使用setter也是 baaad,特别是当一个线程正在使用该对象时.那是非常安全的.

每次给出新信息时我都不想创建新对象,我想将其添加到现有对象中.

没关系,只要你控制对象没有问题,其他一些人可能会发现更容易创建一个新对象.

使用JavaBeans进行数据存储是一种不好的做法,应该避免使用,还是非常安全?

不,这不是一个坏习惯.也不是很安全.取决于情况.

可变对象(不是JavaBeans本身)的问题是使用不同的线程来访问它们.

您必须同步访问权限以避免一个线程修改对象而另一个线程正在访问它.

不可变对象没有这个问题,因为,......它们无法改变,因此,您不必同步任何东西.

要确保对象是不可变的,您必须将属性声明为final.

class MyBean  {
    private final int i;
}
Run Code Online (Sandbox Code Playgroud)

如果要为其分配合理的值,则MyBean.i必须在构造函数中指定它:

 public MyBean( int i ) {
     this.i = i;
 }
Run Code Online (Sandbox Code Playgroud)

由于变量是final,因此您无法使用setter.你可以提供一个吸气剂.

这是完全线程安全的,最好的是,您不必同步访问,因为如果两个线程试图获取i它们的值,它们将始终看到在实例化时分配的值,您不必同步任何东西.

不是不好的做法或良好的做法.我们必须使用单个线程,即使在像servlet这样的多线程环境中也是如此.

如果将来您必须处理多线程应用程序,您可以考虑使用不可变的JavaBean;)

BTW,创建不可变bean的替代方案,并且仍然提供一堆setter使用Builders如下:

 Employee e = new EmployeeBuilder()
                  .setName("Oscar")
                  .setLastName("Reyes")
                  .setAge(0x1F)
                  .setEmployeeId("123forme")
                  .build(); 
Run Code Online (Sandbox Code Playgroud)

这看起来非常类似于常规bean中使用的常规setXyz,具有使用不可变数据的好处.

如果需要更改一个值,可以使用类方法:

 Employee e = Employee.withName( e, "Mr. Oscar");
Run Code Online (Sandbox Code Playgroud)

它采用现有对象,并复制所有值,并设置一个新的....

 public static EmployeeWithName( Employee e , String newName ){
      return new Employee( newName, e.lastName, e.age, e.employeeId );
  }
Run Code Online (Sandbox Code Playgroud)

但同样,在单线程模型中使用getter/setter是完全安全的.

PS我强烈建议你购买这本书:Effective Java.你永远不会后悔,你将有信息来判断更好的文章,如引用.


JUS*_*ION 6

我反对使用JavaBeans作为数据存储类是因为它们允许状态不一致的对象.在这种bean的典型用例中,您有以下步骤:

  • 实例化该类;
  • 设置第一个属性;
  • 设置第二个属性;
  • ...
  • 设置最终属性;
  • 使用对象实例.

现在你的课程已经可以使用了.那么这里的问题是什么?在实例化类和设置最终属性之间,你有一个处于内部不一致或不可用状态的对象,但没有什么能阻止你意外地使用它.我更喜欢一个系统,在实例化时,类会自动处于一致的可用状态.出于这个原因,我更喜欢在构造函数中传递所有初始状态,或者,如果所述初始状态太复杂,则以哈希映射或集合等形式传递初始状态.用例场景现在是:

  • (可选:设置参数对象) ;
  • 实例化该类;
  • 使用对象实例.

在这个工作流程中,我可能无意中开始使用状态不一致的对象.如果我使用一个参数对象,它根本不会直接用于任何东西,它的内容将在我的主类实例化时进行审查.从实例化返回时,主类本身将为我提供一个立即使用的对象实例.

当然,这种设置最适合较简单的对象.对于包含可选属性等更复杂的对象,您需要更进一步,并使用其他人指向您的Builder模式.当你有更复杂的场景,IMO时,构建器很好,但是对于更简单,更直接的参数化,仅仅使用构造函数参数或某种类型的参数对象就足够了.