为什么我不应该使用不可变的POJO而不是JavaBeans?

Jon*_*nas 78 java immutability pojo javabeans

我现在已经实现了一些Java应用程序,到目前为止只有桌面应用程序.我更喜欢使用不可变对象在应用程序中传递数据,而不是使用带有mutator(setter 和getter)的对象,也称为JavaBeans.

但是在Java世界中,使用JavaBeans似乎更常见,我无法理解为什么我应该使用它们.就个人而言,如果代码只处理不可变对象而不是一直改变状态,那么代码看起来会更好.

第15项中还建议使用不可变对象:最小化可变性,有效Java 2ed.

如果我有一个Person实现为JavaBean的对象,它看起来像:

public class Person {
    private String name;
    private Place birthPlace;

    public Person() {}

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

    public setBirthPlace(Place birthPlace) {
        this.birthPlace = birthPlace;
    }

    public String getName() {
        return name;
    }

    public Place getBirthPlace() {
        return birthPlace;
    }
}
Run Code Online (Sandbox Code Playgroud)

并且Person实现为不可变对象:

public class Person {
    private final String name;
    private final Place birthPlace;

    public Person(String name, Place birthPlace) {
        this.name = name;
        this.birthPlace = birthPlace;
    }

    public String getName() {
        return name;
    }

    public Place getBirthPlace() {
        return birthPlace;
    }
}
Run Code Online (Sandbox Code Playgroud)

或者更靠近structC:

public class Person {
    public final String name;
    public final Place birthPlace;

    public Person(String name, Place birthPlace) {
        this.name = name;
        this.birthPlace = birthPlace;
    }
}
Run Code Online (Sandbox Code Playgroud)

我也可以在不可变对象中使用getter来隐藏实现细节.但是因为我只使用它作为struct我喜欢跳过"吸气剂",并保持简单.

简单地说,我不明白为什么使用JavaBeans更好,或者我是否可以而且应该继续使用我的不可变POJO?

许多Java库似乎对JavaBeans有更好的支持,但是对不可变POJO的更多支持随着时间的推移会越来越受欢迎?

JUS*_*ION 76

首选JavaBeans时

  • 您必须与期望它们的环境进行交互
  • 你有很多属性,在实例化时进行所有初始化是不方便的
  • 由于某种原因你需要复制昂贵或无法复制的状态,但需要变异
  • 您认为在某些时候您可能需要更改属性的访问方式(例如,从存储位置移动到计算值,访问权限等)
  • 你想要符合编码标准,这种标准无意识地坚持使用JavaBeans更加"面向对象"

更喜欢不可变的POJO

  • 你有一些简单的属性
  • 假设JavaBean约定,您不必与环境交互
  • 克隆对象时很容易(或者至少可能)复制状态
  • 你根本没有计划克隆对象
  • 你很确定你不必像上面那样修改属性的访问方式
  • 你不介意听到抱怨(或嘲笑)你的代码如何不充分"面向对象"

  • 你在bean中的第二点不支持bean,而是支持Builder模式.您仍然可以构造一个不可变对象. (24认同)
  • 可以在构造函数中完成边界检查和输入验证.如果输入无效或超出范围,我不想创建对象. (12认同)
  • 您没有提到使用不可变POJO的线程,这是使用它们的最大原因之一.另一个重要的项目是简单性 - 当一个对象没有改变时,从长远来看它更容易使用.此外,对于不可变的POJO,您不必担心一般克隆对象,您可以只传递它. (4认同)

Ben*_*ton 39

我很惊讶Thread这个词在这个讨论中没有出现过.

不可变类的一个主要好处是,由于没有可变的共享状态,它们本质上更加线程安全.

这不仅可以使您的编码更容易,而且还可以为您带来两个性能优势:

  • 减少同步需求.

  • 更多使用final变量的范围,这可以促进后续的编译器优化.

我真的想对不可变对象,而不是JavaBean风格的类运动.通过getter和setter揭露对象的胆量可能不应该是默认的选择.


And*_*anu 16

那取决于你想要做什么.如果您使用持久层,并从数据库中获取某些行到POJO,并且您想要更改属性并将其保存回来,那么使用JavaBean样式会更好,特别是如果您有很多属性.

考虑到你的人,有很多领域,如,第一,中间,姓氏,出生日期,家庭成员,教育,工作,工资等.

那个人恰好是一个刚刚结婚并被接受更改姓氏的女性,你需要更新数据库.

如果你正在使用不可变的POJO,你获取一个代表她的Person对象,然后你创建一个新的Person对象,你传递所有你没有按原样改变的属性和新的姓氏,然后保存它.

如果它是Java bean,你可以只做setLastName()并保存它.

这是'最小化可变性'而不是'永远不会使用可变对象'.有些情况下可变对象的效果更好,确定一个对象是否可变更适合你的程序真的是你的工作.你不应该总是说'必须使用不可变对象',而是在你开始伤害自己之前看看有多少个类可以变成不可变的.

  • 但您的示例几乎从来都不是“真实”应用程序中需要完成的事情。通常,更新的数据对象需要传递到验证框架(Hibernate Validator、Spring Validator 等),其中对象会受到可能由不同开发人员编写的各种操作的影响。如果对象是可变的,您不知道您是否正在使用传入的相同数据(如果在您之前执行的某些验证使对象发生了突变)。它使验证过程的决定性更小,更依赖于严格的顺序,并且不可并行。 (2认同)

hel*_*ios 7

总结其他答案我认为:

  • Inmutability利于正确性(结构可以通过引用传递,你什么都不知道会出现故障/恶意的客户端被破坏),并简化代码
  • 可变性有利于均匀性:Spring和其他框架建立,不带参数的对象,设置对象的属性,以及VOILà.也使接口更方便使用相同的类让数据和保存修改(你不需要get(id): Clientsave(MutableClient),是MutableClient客户端的一些后裔.

如果存在中间点(create,set properties,make inmutable),那么框架可能会鼓励更多不可改变的方法.

无论如何,我建议将不可变对象视为"只读Java Bean",强调如果你是一个好孩子并且不触及那个危险的setProperty方法,一切都会好的.